using System.Collections.Generic;
using System.Linq;
using Consulenza.ReportWriter.Business.Entity;
using ceTe.DynamicPDF;
using Dundas.Charting.WebControl;
using Consulenza.ReportCommon;
using System;
using Consulenza.ReportWriter.Business.OBJ_PDF;
using System.Web;
using ceTe.DynamicPDF.PageElements;
using Consulenza.ReportWriter.Business;
using Consulenza.ReportWriter.Business.CUSTOM_PDF.ConsulenzaUnica;

namespace Consulenza.ReportWriter.Business.CHART_PDF
{
    public class CombinationPDF : ChartPDF
    {
        private ReportEnvironment reportEnvironment;

        private double _maximumAxisY = 0;
        private double _minimumAxisY = 0;
        private double _maximumAxisX = 0;
        private double _minimumAxisX = 0;
        private double _intervalY = 0;
        private double _intervalX = 0;
        private float _legendYOffset = 0;
        // Variabili usate quando XValueType = Date o DateTime
        private DateTime _minimumDate = DateTime.Today;
        private DateTime _maximumDate = DateTime.Today;
        private int _intervalDays = 0;
        private int _intervalMonths = 0;
        private float _chartBaseHeight = 0;
        private float _chartBaseWidth = 0;
        private bool _removeWhiteSpacesY = false;
        private bool _showZeroInLabel = false;


        #region Field
        public bool EqualDateLabelDistanceAxisX { get; set; }
        /// <summary>
        /// bool che indica se mostrare la legenda. Di default = false.
        /// </summary>

        public float AxisYMinimumValueOffset { get; set; }
        public bool ShowLegend { get; set; }

        public bool CalculateCustomIntegerLabelsAxisY { get; set; }

        public void SetReportEnvironment(ReportEnvironment reportEnvironment)
        {
            this.reportEnvironment = reportEnvironment;
        }
public bool showZeroInLabel {
            get {   return _showZeroInLabel;    }
            set {   _showZeroInLabel = value;   }
        }
        public bool RemoveWhiteSpacesY
        {
            get
            {
                return _removeWhiteSpacesY;
            }
            set
            {
                _removeWhiteSpacesY = value;
            }
        }
        /// <summary>
        /// Lista di interi che rappresentano le larghezze personalizzabili delle colonne della tabella che compone la Leggenda.
        /// Colonna1: Immagine, Colonna2: Spazio, Colonna3: Testo.
        /// Di default = (20,15,125)
        /// </summary>
        public List<int> LegendWidthColumns { get; set; }

        public float LegendYOffset
        {
            get
            {
                return _legendYOffset;
            }
            set
            {
                _legendYOffset = value;
            }
        }

        /// <summary>
        /// Imposta o recupera l'altezza del simbolo della colonna1 della tabella che compone la legenda.
        /// Di default= 10.
        /// </summary>
        public float LegendSymbolHeight { get; set; }

        /// <summary>
        /// Imposta o recupera il delta Y (intesto come spostamento in alto in basso della Y del simbolo della legenda).
        /// Di default=4.
        /// </summary>
        public float LegendSymbolDeltaY { get; set; }

        public float InnerChartDeltaY { get; set; }

        public float ChartBaseHeight
        {
            get
            {
                return _chartBaseHeight;
            }
            set
            {
                ChartBase.Height = (System.Web.UI.WebControls.Unit)value;
                _chartBaseHeight = value;
            }
        }



        public float? AxisXMaximum { get; set; }

        public float? AxisXMinimum { get; set; }

        public float ChartBaseWidth
        {
            get
            {
                return _chartBaseWidth;
            }
            set
            {
                ChartBase.Width = (System.Web.UI.WebControls.Unit)value;
                _chartBaseWidth = value;
            }
        }
        /// <summary>
        /// Imposta o recupera il delta X (intesto come spostamento a destra o sinistra della X della legenda).
        /// Di default=0.
        /// </summary>
        public float LegendDeltaX { get; set; }

        /// <summary>
        /// Imposta o recupera il font size del testo della legenda.
        /// Di default= 8.
        /// </summary>
        public int LegendFontSizeText { get; set; }

        /// <summary>
        /// bool che indica se mostrare il border top. Di default = false.
        /// </summary>
        public bool BorderLineTop { get; set; }

        /// <summary>
        /// Imposta o recupera la X di BorderLineTop quando BorderLineTop = true.
        /// </summary>
        public float BorderLineX { get; set; }

        /// <summary>
        /// Imposta o recupera la Width di BorderLineTop quando BorderLineTop = true.
        /// </summary>
        public float BorderLineWidth { get; set; }

        /// <summary>
        /// Imposta o recupera un bool che indica se mostare la linea sull'asse y in corrispondeza dell'intervallo.
        /// Di default = false.
        /// </summary>
        public bool MinorGridAxisY { get; set; }

        /// <summary>
        /// Imposta o recupera il margine nell'asse y.
        /// Di default = 7.
        /// </summary>
        public float MarginAxisY { get; set; }

        /// <summary>
        /// Imposta o recupera un bool che indica se mostrare la linea dell'asse Y.
        /// Di default = True.
        /// </summary>
        public bool ShowLineAxisY { get; set; }

        /// <summary>
        /// Imposta o recupera un bool che indica se mostrare la linea dell'asse X.
        /// Di default = False.
        /// </summary>
        public bool ShowLineAxisX { get; set; }

        /// <summary>
        /// Imposta o recupera il numero di intervalli per l'asse Y.
        /// Di default = 4.
        /// </summary>
        public int IntervalNumberAxisY { get; set; }

        /// <summary>
        /// Imposta o recupera il tipo di formato delle etichette dell'asse Y.
        /// Di default = FormatType.Intero
        /// </summary>
        public FormatType LabelFormatAxisY { get; set; }

        /// <summary>
        /// Imposta o recupera il tipo di formato delle etichette dell'asse X.
        /// Di default = FormatType.Intero
        /// </summary>
        public FormatType LabelFormatAxisX { get; set; }

        /// <summary>
        /// Imposta o recupera un bool che indica se mostrare le label dell'asse Y.
        /// Di default = True.
        /// </summary>
        public bool ShowLabelAxisY { get; set; }

        /// <summary>
        /// Imposta o recupera un bool che indica se mostrare le label dell'asse X.
        /// Di default = True.
        /// </summary>
        public bool ShowLabelAxisX { get; set; }

        /// <summary>
        /// Imposta o recupera il numero di intervalli per l'asse X.
        /// Di default = 4.
        /// </summary>
        public int IntervalNumberAxisX { get; set; }

        /// <summary>
        /// Imposta o recupera un bool che indica che l'asse X partirà da 0.
        /// Di default = false.
        /// </summary>
        public bool StartFromZeroAxisX { get; set; }

        /// <summary>
        /// Imposta o recupera un bool che indica che l'asse Y partirà da 0.
        /// Di default = false.
        /// </summary>
        public bool StartFromZeroAxisY { get; set; }

        /// <summary>
        /// Imposta o recupera il nome dell'immagine di sfondo del grafico.
        /// Di default = string.empty (nessuna immagine).
        /// </summary>
        public string BackImage { get; set; }

        /// <summary>
        /// Imposta o recupera il colore di sfondo del grafico.
        /// Di default = Bianco.
        /// </summary>
        public ColorPDF BackColor { get; set; }

        /// <summary>
        /// Imposta o recupera l'indicatore dell'asse Y.
        /// Di default null = nessuna renderizzazione.
        /// </summary>
        public CombinationPDFIndicator? IndicatorAxisY { get; set; }

        /// <summary>
        /// Imposta o recupera l'indicatore dell'asse X.
        /// Di default null = nessuna renderizzazione.
        /// </summary>
        public CombinationPDFIndicator? IndicatorAxisX { get; set; }

        /// <summary>
        /// Imposta o recupera la lista di label personalizzate dell'asse Y
        /// </summary>
        public List<CombinationPDFCustomLabel> CustomLabelAxisY { get; set; }

        /// <summary>
        /// Imposta o recupera la lista di label personalizzate dell'asse X
        /// </summary>
        public List<CombinationPDFCustomLabel> CustomLabelAxisX { get; set; }

        public bool ShowCustomLabelsAxisX { get; set; }
        /// <summary>
        /// Imposta o recupera il valore massimo dell'asse Y.
        /// Quando è 0 il valore massimo è preso tra i valori aggiunti ai Points delle Series.
        /// Di default = 0.
        /// </summary>
        public double MaximumValueAxisY { get; set; }


        public double MinimumValueAxisY { get; set; }

        public bool DontCalculateMaxAndMinAxisY { get; set; }
        /// <summary>
        /// Imposta o recupera il valore massimo dell'asse X.
        /// Quando è 0 il valore massimo è preso tra i valori aggiunti ai Points delle Series.
        /// Di default = 0.
        /// </summary>
        public double MaximumValueAxisX { get; set; }

        /// <summary>
        /// Imposta o recupera un bool che indica se mostrare lo 0 sull'asse delle Y.
        /// di default= false.
        /// </summary>
        public bool ShowMarginX { get; set; }

        ///// <summary>
        ///// Imposta o recupera un bool che indica se mostrare un margine (definito da dundas) e l'inizio delle barre sull'asse X.
        ///// Di default= false.
        ///// </summary>
        //public bool ShowMarginX { get; set; }

        ///// <summary>
        ///// Imposta o recupera un bool che indica se mostrare un margine (definito da dundas) e l'inizio delle barre sull'asse Y.
        ///// Di default= false.
        ///// </summary>
        //public bool ShowMarginY { get; set; }

        #endregion

        #region Costruttori

        /// <summary>
        /// Costruttore
        /// </summary>
        public CombinationPDF()
        {
            ObjectType = ObjectTypePdf.CHART;
            ChartType = ChartTypePdf.COMBINATION;
            ChartBase.ChartAreas.Add("Default");

            BackColor = ColorPDF.Bianco;

            // Imposto la ChartAreas di default in modalidtà 3D
            ChartBase.ChartAreas["Default"].Area3DStyle.Enable3D = true;
            ChartBase.ChartAreas["Default"].Area3DStyle.XAngle = 5;

            // Legenda disabilitata
            ChartBase.Legend.Enabled = false;

            MinorGridAxisY = false;
            MarginAxisY = 7;

            ShowLineAxisX = false;
            ShowLineAxisY = true;

            ShowLabelAxisX = true;
            ShowLabelAxisY = true;

            IntervalNumberAxisX = 4;
            IntervalNumberAxisY = 4;

            LabelFormatAxisY = FormatType.Intero;
            LabelFormatAxisX = FormatType.Intero;

            LegendWidthColumns = new List<int>() { 20, 15, 125 };
            LegendSymbolHeight = 10;
            LegendFontSizeText = 7;

            BackImage = string.Empty;

            IndicatorAxisX = null;
            IndicatorAxisY = null;

            CustomLabelAxisY = new List<CombinationPDFCustomLabel>();
            CustomLabelAxisX = new List<CombinationPDFCustomLabel>();
        }

        /// <summary>
        /// Costruttore
        /// </summary>
        /// <param name="x"></param>
        public CombinationPDF(float x)
            : this()
        {
            X = x;
        }

        /// <summary>
        /// Costruttore
        /// </summary>
        /// <param name="x"></param>
        /// <param name="scale"></param>
        public  CombinationPDF(float x, float scale)
            : this(x)
        {
            Scale = scale;
        }

        /// <summary>
        /// Costruttore
        /// </summary>
        /// <param name="x"></param>
        /// <param name="scale"></param>
        /// <param name="y"></param>
        public CombinationPDF(float x, float scale, float y)
            : this(x, scale)
        {
            Y = y;
        }

        #endregion

        #region Metodi

        /// <summary>
        /// Cerca in tutti i Points aggiunti alla SeriesCollection e ne recupera il Values.Y massimo.
        /// </summary>
        /// <returns></returns>
        public double GetMaximumValueYPoints()
        {
            return SeriesCollection.SelectMany(a => a.Points, (a, b) => b.Values.Y).Max();
        }

        /// <summary>
        /// Cerca in tutti i Points aggiunti alla SeriesCollection e ne recupera il Values.Y minimo.
        /// </summary>
        /// <returns></returns>
        public double GetMinimumValueYPoints()
        {
            return SeriesCollection.SelectMany(a => a.Points, (a, b) => b.Values.Y).Min();
        }

        /// <summary>
        /// Cerca in tutti i Points aggiunti alla SeriesCollection e ne recupera il Values.X massimo.
        /// </summary>
        /// <returns></returns>
        public double GetMaximumValueXPoints()
        {
            return SeriesCollection.SelectMany(a => a.Points, (a, b) => b.Values.X).Max();
        }

        /// <summary>
        /// Cerca in tutti i Points aggiunti alla SeriesCollection e ne recupera il Values.X minimo.
        /// </summary>
        /// <returns></returns>
        public double GetMinimunValueXPoints()
        {
            return SeriesCollection.SelectMany(a => a.Points, (a, b) => b.Values.X).Min();
        }

        /// <summary>
        /// Converte in ObjectPDF l'oggetto PiePDF (ChartPDF). 
        /// </summary>
        /// <returns></returns>
        public override PageElement ToElement()
        {
            var listReturn = new List<ObjectPDF>();

            #region Creo il grafico

            CreateChart();
            #endregion

            #region Ritorno l'immagine contenente il grafico
            var image = ToImage();
            listReturn.Add(image);
            image.DeltaY = InnerChartDeltaY;
            TotalHeight += Height;

            #endregion

            #region Ritorno la linea, le etichette e l'indicatore dell'Asse Y

            listReturn.Add(new SpacePDF(Height + MarginAxisY));
            TotalHeight += MarginAxisY;

            #region Linea dell' asse Y

            if (ShowLineAxisY)
                listReturn.Add(new LinePDF(X, X) { DeltaY2ForVerticalLine = -(Height + MarginAxisY) });

            #endregion

            #region Etichette dell' asse Y

            var counter = 0;

            if (ShowLabelAxisY)
            {
                const float larghezzaMarcatoreAsseY = 5;
                const float larghezzaEtichettaAsseY = 100F;

                // Etichetta asse Y               
                var valoreEtichettaAsseY = _minimumAxisY;

                if (LabelFormatAxisY != FormatType.Data && LabelFormatAxisY != FormatType.DataShort && !DontCalculateMaxAndMinAxisY)
                    valoreEtichettaAsseY = _minimumAxisY >= 0 ? 0 : _minimumAxisY;

                #region Show Zero on Axis Y
                if (showZeroInLabel)
                {
                    List<double> valueList = new List<double>();
                    List<float> distanceList = new List<float>();
                    bool replacedValue = false;
                    bool showValue = true;
                    int index = -1;

                    //  Get all the interval values
                    for (int i = 0; i <= IntervalNumberAxisY; i++)
                        valueList.Add((double)valoreEtichettaAsseY + (_intervalY*i));

                    var minAbsValue = valueList.Where(x => x != _minimumAxisY).Min();
                    if (Math.Abs(_minimumAxisY) > Math.Abs(minAbsValue) && Math.Min(Math.Abs(_minimumAxisY), Math.Abs(minAbsValue)) <= 2)
                    {
                        double toReplace = minAbsValue;
                        int indexToReplace = valueList.FindIndex(x => x == toReplace);
                        valueList[indexToReplace] = 0d;
                        replacedValue = true;
                    }
                    else
                    {
                        valueList.Add((double)0d);
                        valueList.Sort();
                        IntervalNumberAxisY++;
                    }
                    var spaceBetweenLabel = -(Height / (replacedValue ? IntervalNumberAxisY : IntervalNumberAxisY - 1));

                    for (int i = 0; i < valueList.Count() - 1; i++)
                    {
                        var toRound = spaceBetweenLabel * (valueList[i + 1] - valueList[i]) / _intervalY;
                        if (Math.Abs(toRound) < 6.0)
                            index = valueList[i] == 0 ? i + 1 : i;
                        distanceList.Add(Convert.ToSingle(toRound));

                    }

                    counter = 0;
                    do
                    {
                        showValue = counter != index ? true : false;
                        valoreEtichettaAsseY = valueList[counter];

                        #region Marcatore asse Y presente solo de ShowLineAxisY = true

                        if (ShowLineAxisY)
                            if (showValue)
                            {
                                listReturn.Add(new LinePDF(X, X - larghezzaMarcatoreAsseY, 0.5F) { AutoIncrementYWritable = false });

                                #endregion

                        #region Label
                                listReturn.Add(new FormattedTextAreaPDF(Helper.FormatPercentage(Convert.ToString(valoreEtichettaAsseY), 0), (X - larghezzaEtichettaAsseY - larghezzaMarcatoreAsseY - 2), larghezzaEtichettaAsseY)
                                {
                                    TextHorizontalAlign = TextAlign.Right,
                                    AutoIncrementYWritable = false,
                                    FontSize = 7,
                                    DeltaY = -(4) //(-4 derviva da: FontSize / 2)
                                });
                            }
                                #endregion

                        #region Grid
                        //Creation of the grid with the chosen style
                        if (valueList[counter] != _minimumAxisY && showValue)
                        {
                            listReturn.Add(new LinePDF()
                            {
                                X1 = X,
                                X2 = X + Width,
                                Color = ColorPDF.ConsulenzaBase_Grigio_SfondoColonnaHeaderFooterTabella,
                                Width = 0.20F,
                                AutoIncrementYWritable = false,
                                BorderStyle = LineStyle.Dots
                            });
                        }
                        #endregion

                        #region Space between labels
                        //Decreasing space for the next label
                        if (counter < IntervalNumberAxisY)
                            listReturn.Add(new SpacePDF(distanceList[counter]));
                        #endregion

                        counter++;
                    }
                    while (counter <= IntervalNumberAxisY);
                }
                #endregion

                else
                {

                if (CalculateCustomIntegerLabelsAxisY)
                {
                    int range = (int)_maximumAxisY - (int)_minimumAxisY;
                    int minValue = (int)_minimumAxisY;
                    int maxValue = (int)_maximumAxisY;
                    int offset = (int)(Math.Round((double)(range / 7)));
                    int counterIntervals = 0;
                    for (int i = minValue; i <= maxValue; i += offset)
                    {
                        CustomLabelAxisY.Add(new CombinationPDFCustomLabel() { Text = ((double)i).ToString("F"), Value = i });
                        counterIntervals++;
                    }
                    IntervalNumberAxisY = counterIntervals;
                }

                if (CustomLabelAxisY.Any())
                {
                    #region Label personalizzate
                    counter = 0;
                    do
                    {
                        // Calcolo dello spazio in cui disegnare la custom label dall'inizio del grafico in funzione del valore della CustomLabelAxisY corrente.
                        float spazioCustomLabelYDaInizioGrafico = 0;
                        if (CustomLabelAxisY[counter].Value >= 0)
                        {
                            float tmpHeight = Height * (float)_maximumAxisY / ((float)_maximumAxisY - (float)_minimumAxisY);
                            spazioCustomLabelYDaInizioGrafico = tmpHeight - (tmpHeight / (float)(_maximumAxisY / CustomLabelAxisY[counter].Value));
                        }
                        else
                        {
                            float positiveHeight = Height * (float)_maximumAxisY / ((float)_maximumAxisY - (float)_minimumAxisY);
                            float negativeHeight = Height * (float)Math.Abs(_minimumAxisY) / ((float)_maximumAxisY - (float)_minimumAxisY);
                            spazioCustomLabelYDaInizioGrafico = positiveHeight + (negativeHeight / (float)(Math.Abs(_minimumAxisY) / Math.Abs(CustomLabelAxisY[counter].Value)));
                        }

                        listReturn.Add(new SpacePDF(-(Height - spazioCustomLabelYDaInizioGrafico)));

                        #region Marcatore asse Y presente solo de ShowLineAxisY = true

                        if (ShowLineAxisY)
                            listReturn.Add(new LinePDF(X, X - larghezzaMarcatoreAsseY, 0.5F) { AutoIncrementYWritable = false });

                        #endregion

                        // Etichetta asse Y
                        listReturn.Add(new FormattedTextAreaPDF(CustomLabelAxisY[counter].Text, X - larghezzaEtichettaAsseY - larghezzaMarcatoreAsseY - 2, larghezzaEtichettaAsseY)
                        {
                            TextHorizontalAlign = TextAlign.Right,
                            AutoIncrementYWritable = false,
                            FontSize = 7,
                            DeltaY = -(4) //(-4 derviva da: FontSize / 2)
                        });

                        counter++;

                        if (counter < IntervalNumberAxisY)
                            listReturn.Add(new SpacePDF(Height - spazioCustomLabelYDaInizioGrafico)); // Torno alla fine del grafico (origine)
                        else
                            listReturn.Add(new SpacePDF(-spazioCustomLabelYDaInizioGrafico)); // Mi posiziono all'inizio del grafico
                    }
                    while (counter < IntervalNumberAxisY);
                    #endregion
                }
                else
                {
                    #region Label ad incremento standard
                    counter = 0;
                    do
                    {
                        #region Marcatore asse Y presente solo de ShowLineAxisY = true

                        if (ShowLineAxisY)
                            listReturn.Add(new LinePDF(X, X - larghezzaMarcatoreAsseY, 0.5F) { AutoIncrementYWritable = false });

                        #endregion

                        #region Testo etichetta asse Y

                        var sEtichettaAsseY = string.Empty; // Etichetta asse Y
                        switch (LabelFormatAxisY)
                        {
                            case FormatType.Intero:
                                sEtichettaAsseY = Helper.FormatInteger(Convert.ToString(valoreEtichettaAsseY));
                                break;
                            case FormatType.Decimale0:
                                sEtichettaAsseY = Helper.FormatDecimal(Convert.ToString(valoreEtichettaAsseY), 0);
                                break;
                            case FormatType.Decimale1:
                                sEtichettaAsseY = Helper.FormatDecimal(Convert.ToString(valoreEtichettaAsseY), 1);
                                break;
                            case FormatType.Decimale2:
                                sEtichettaAsseY = Helper.FormatDecimal(Convert.ToString(valoreEtichettaAsseY), 2);
                                break;
                            case FormatType.Decimale2ConSeparatore:
                                sEtichettaAsseY = Helper.FormatCurrency(Convert.ToString(valoreEtichettaAsseY));
                                break;
                            case FormatType.Valuta:
                                sEtichettaAsseY = Helper.FormatCurrencyWithSymbol(Convert.ToString(valoreEtichettaAsseY));
                                break;
                            case FormatType.Percentuale:
                                sEtichettaAsseY = Helper.FormatPercentage(Convert.ToString(valoreEtichettaAsseY), 0);
                                break;
                            case FormatType.Data:
                                sEtichettaAsseY = DateTime.FromOADate(valoreEtichettaAsseY).ToString();
                                break;
                            case FormatType.DataShort:
                                sEtichettaAsseY = DateTime.FromOADate(valoreEtichettaAsseY).ToShortDateString();
                                break;
                            case FormatType.PercentualeImmobiliare:
                                sEtichettaAsseY = Helper.FormatPercentage(Convert.ToString(valoreEtichettaAsseY), 1);
                                break;
                        }
                        #endregion

                        listReturn.Add(new FormattedTextAreaPDF(sEtichettaAsseY, (X - larghezzaEtichettaAsseY - larghezzaMarcatoreAsseY - 2), larghezzaEtichettaAsseY)
                        {
                            TextHorizontalAlign = TextAlign.Right,
                            AutoIncrementYWritable = false,
                            FontSize = 7,
                            DeltaY = -(4) //(-4 derviva da: FontSize / 2)
                        });

                        // Incremento valoreEtichettaAsseY
                        valoreEtichettaAsseY += _intervalY;

                        //Decremento lo spazio su cui andrà a posizionarsi la prossima etichetta
                        if (counter < IntervalNumberAxisY)
                            listReturn.Add(new SpacePDF(-(Height / IntervalNumberAxisY)));

                            counter++;
                        }
                        while (counter <= IntervalNumberAxisY);
                        #endregion
                    }
                }////////

            }
            #endregion

            #region Indicatore dell' asse Y

            if (IndicatorAxisY.HasValue)
            {
                const int altezzaRettangoloIndicatoreAsseY = 30;
                const int larghezzaRettangoloIndicatoreAsseY = 70;

                // Calcolo dello spazio in cui disegnare l'indicatore dall'inizio del grafico.
                var spazioIndicatoreYDaInizioGrafico = Height - (Height / (float)(_maximumAxisY / IndicatorAxisY.Value.Value));
                listReturn.Add(new SpacePDF(spazioIndicatoreYDaInizioGrafico));

                //Rettangolo che forma la punta
                listReturn.Add(new RectanglePDF(X + IndicatorAxisY.Value.DeltaX + larghezzaRettangoloIndicatoreAsseY, altezzaRettangoloIndicatoreAsseY / 1.414F, altezzaRettangoloIndicatoreAsseY / 1.414F, ColorPDF.Standard_Grigio_SfondoColonnaTabella) { AutoIncrementYWritable = false, DeltaY = -(altezzaRettangoloIndicatoreAsseY / 2), Angle = 45 });

                //Rettangolo contenitore
                listReturn.Add(new RectanglePDF(X + IndicatorAxisY.Value.DeltaX, altezzaRettangoloIndicatoreAsseY, larghezzaRettangoloIndicatoreAsseY, ColorPDF.Standard_Grigio_SfondoColonnaTabella) { AutoIncrementYWritable = false, DeltaY = -(altezzaRettangoloIndicatoreAsseY / 2) });

                // Testo
                listReturn.Add(new FormattedTextAreaPDF(IndicatorAxisY.Value.Text, X + IndicatorAxisY.Value.DeltaX + 2, larghezzaRettangoloIndicatoreAsseY) { FontBold = true, FontSize = 7, AutoIncrementYWritable = false, DeltaY = IndicatorAxisY.Value.DeltaYText });

                // Reset spazio
                listReturn.Add(new SpacePDF(-(spazioIndicatoreYDaInizioGrafico)));
            }

            #endregion

            #endregion

            #region Ritorno la linea e le etichette dall'Asse X

            listReturn.Add(new SpacePDF(Height));

            #region  Linea dell' asse X

            if (ShowLineAxisX)
                listReturn.Add(new LinePDF(X, (X + Width)));

            #endregion

            #region Etichette dell' asse X

            if (ShowLabelAxisX)
            {
                const float larghezzaMarcatoreAsseX = 5;
                const float larghezzaEtichettaAsseX = 100F;
                var xMarcatoreAsseX = X;

                // Intervallo
                var larghezzaIntervallo = Width / IntervalNumberAxisX;

                // Etichetta asse X               
                var valoreEtichettaAsseX = _minimumAxisX;

                if (LabelFormatAxisX != FormatType.Data && LabelFormatAxisX != FormatType.DataShort && LabelFormatAxisX != FormatType.DataSenzaOra)
                    valoreEtichettaAsseX = _minimumAxisX >= 0 ? 0 : _minimumAxisX;

                if (CustomLabelAxisX.Any())
                {
                    #region Label personalizzate
                    if (ShowCustomLabelsAxisX)
                    {
                        var minValueAxisX = ChartBase.ChartAreas[0].AxisX.Minimum;
                        var maxValueAxisX = ChartBase.ChartAreas[0].AxisX.Maximum;
                        var axisXValueWidth = maxValueAxisX - minValueAxisX;
                        foreach (var customLabel in CustomLabelAxisX)
                        {
                            var xLabelPosition = (1 - (maxValueAxisX - customLabel.Value) / axisXValueWidth) * ChartBaseWidth + X;
                            listReturn.Add(new LinePDF((float)xLabelPosition, (float)xLabelPosition, 0.5F) { DeltaY2ForVerticalLine = larghezzaMarcatoreAsseX });

                            var label = new FormattedTextAreaPDF(customLabel.Text, 0)
                            {
                                AutoIncrementYWritable = false,
                                DeltaY = larghezzaMarcatoreAsseX + 1
                            };
                            if (reportEnvironment == null)
                            {
                                throw new ApplicationException("Use SetReportEnvironment() method first, in order to use GetWidthReal method");
                            }
                            var labelWidth = label.GetWidthReal(reportEnvironment.FontFamily, false);
                            label.X = (float)xLabelPosition - labelWidth / 2;
                            listReturn.Add(label);
                        }
                    }
                    else
                    {
                        counter = 0;
                        do
                        {
                            //Incremento X
                            xMarcatoreAsseX = X;
                            var incrementoAsseX = (Width / (float)_maximumAxisX) * (float)CustomLabelAxisX[counter].Value;
                            xMarcatoreAsseX += incrementoAsseX;

                            #region Marcatore asse X presente solo de ShowLineAxisX = true

                            if (ShowLineAxisX)
                                listReturn.Add(new LinePDF(xMarcatoreAsseX, xMarcatoreAsseX, 0.5F) { DeltaY2ForVerticalLine = larghezzaMarcatoreAsseX });

                            #endregion

                            counter++;
                        }
                        while (counter < IntervalNumberAxisX);
                    }
                    

                    #endregion
                }
                else
                {
                    #region Label ad incremento standard
                    counter = 0;
                    do
                    {
                        #region Marcatore asse X presente solo de ShowLineAxisX = true

                        if (ShowLineAxisX)
                            listReturn.Add(new LinePDF(xMarcatoreAsseX, xMarcatoreAsseX, 0.5F) { DeltaY2ForVerticalLine = larghezzaMarcatoreAsseX });

                        #endregion

                        #region Testo etichetta asse X

                        var sEtichettaAsseX = string.Empty; // Etichetta asse X
                        float centralabel = 0;
                        switch (LabelFormatAxisX)
                        {
                            case FormatType.Intero:
                                centralabel = xMarcatoreAsseX - 5;
                                sEtichettaAsseX = Helper.FormatInteger(Convert.ToString(valoreEtichettaAsseX));
                                break;
                            case FormatType.Decimale0:
                                centralabel = xMarcatoreAsseX - 5;
                                sEtichettaAsseX = Helper.FormatDecimal(Convert.ToString(valoreEtichettaAsseX), 0);
                                break;
                            case FormatType.Decimale1:
                                centralabel = xMarcatoreAsseX - 5;
                                sEtichettaAsseX = Helper.FormatDecimal(Convert.ToString(valoreEtichettaAsseX), 1);
                                break;
                            case FormatType.Decimale2:
                                centralabel = xMarcatoreAsseX - 8;
                                sEtichettaAsseX = Helper.FormatDecimal(Convert.ToString(valoreEtichettaAsseX), 2);
                                break;
                            case FormatType.Decimale2ConSeparatore:
                                centralabel = xMarcatoreAsseX - 8;
                                sEtichettaAsseX = Helper.FormatCurrency(Convert.ToString(valoreEtichettaAsseX));
                                break;
                            case FormatType.Valuta:
                                centralabel = xMarcatoreAsseX - 8;
                                sEtichettaAsseX = Helper.FormatCurrencyWithSymbol(Convert.ToString(valoreEtichettaAsseX));
                                break;
                            case FormatType.Percentuale:
                                centralabel = xMarcatoreAsseX - 8;
                                sEtichettaAsseX = Helper.FormatPercentage(Convert.ToString(valoreEtichettaAsseX), 0);
                                break;
                            case FormatType.PercentualeImmobiliare:
                                centralabel = xMarcatoreAsseX - 8;
                                sEtichettaAsseX = Helper.FormatPercentage(Convert.ToString(valoreEtichettaAsseX), 1);
                                break;
                            case FormatType.Data:
                                centralabel = xMarcatoreAsseX - 15;
                                sEtichettaAsseX = DateTime.FromOADate(valoreEtichettaAsseX).ToString();
                                break;
                            case FormatType.DataShort:
                                centralabel = xMarcatoreAsseX - 10;
                                sEtichettaAsseX = DateTime.FromOADate(valoreEtichettaAsseX).ToString("MM/yy");
                                break;
                            case FormatType.MeseAnno:
                                centralabel = xMarcatoreAsseX - 10;
                                sEtichettaAsseX = DateTime.FromOADate(valoreEtichettaAsseX).ToString("MMM-yy");
                                //sEtichettaAsseX = DateTime.ParseExact(valoreEtichettaAsseX.ToString(), "MMM-yy", new System.Globalization.CultureInfo("it-IT")).ToString();
                                break;
                            case FormatType.DataSenzaOra:
                                centralabel = xMarcatoreAsseX - 20;
                                sEtichettaAsseX = DateTime.FromOADate(valoreEtichettaAsseX).ToString("dd/MM/yyyy");
                                break;
                        }
                        #endregion


                        listReturn.Add(new FormattedTextAreaPDF(sEtichettaAsseX, centralabel, larghezzaIntervallo)
                        {
                            TextHorizontalAlign = TextAlign.Left,
                            AutoIncrementYWritable = false,
                            FontSize = 7,
                            DeltaY = larghezzaMarcatoreAsseX + 2
                        });

                        // Incremento valoreEtichettaAsseX
                        if (EqualDateLabelDistanceAxisX)
                        {
                            valoreEtichettaAsseX = DateTime.FromOADate(valoreEtichettaAsseX).AddMonths(_intervalMonths).ToOADate();
                        }
                        else
                        {
                            valoreEtichettaAsseX += _intervalX;
                        }

                        //Incremento X
                        xMarcatoreAsseX += larghezzaIntervallo;

                        counter++;
                    }
                    while (counter <= IntervalNumberAxisX);
                    #endregion
                }
            }
            #endregion

            #region Indicatore dell' asse X

            if (IndicatorAxisX.HasValue)
            {
                const int altezzaRettangoloIndicatoreAsseX = 25;
                const int larghezzaRettangoloIndicatoreAsseX = 50;

                listReturn.Add(new SpacePDF(altezzaRettangoloIndicatoreAsseX * 1.414F));

                //Incremento X                          
                var xIndicatoreAsseX = ((Width / (float)_maximumAxisX) * (float)IndicatorAxisX.Value.Value) - larghezzaRettangoloIndicatoreAsseX / 2;

                // Rettangolo punta
                listReturn.Add(new RectanglePDF(X + xIndicatoreAsseX + IndicatorAxisX.Value.DeltaX + (larghezzaRettangoloIndicatoreAsseX / 2), (float)larghezzaRettangoloIndicatoreAsseX / 1.414F, larghezzaRettangoloIndicatoreAsseX / 1.414F, ColorPDF.Standard_Grigio_SfondoColonnaTabella) { Angle = 45F, DeltaY = -(altezzaRettangoloIndicatoreAsseX) });

                //Rettangolo contenitore
                listReturn.Add(new RectanglePDF(X + xIndicatoreAsseX + IndicatorAxisX.Value.DeltaX, altezzaRettangoloIndicatoreAsseX, larghezzaRettangoloIndicatoreAsseX, ColorPDF.Standard_Grigio_SfondoColonnaTabella) { AutoIncrementYWritable = false, DeltaY = -(altezzaRettangoloIndicatoreAsseX * 1.414F) });

                // Testo
                listReturn.Add(new FormattedTextAreaPDF(IndicatorAxisX.Value.Text, X + xIndicatoreAsseX + IndicatorAxisX.Value.DeltaX + 2, larghezzaRettangoloIndicatoreAsseX) { FontBold = true, FontSize = 7, DeltaY = -(altezzaRettangoloIndicatoreAsseX * 1.600F), DeltaX = IndicatorAxisX.Value.DeltaXText });
            }

            #endregion

            #endregion

            // custom markers
            double maxAxisXVal = ChartBase.ChartAreas[0].AxisX.Maximum;
            double minAxisXVal = ChartBase.ChartAreas[0].AxisX.Minimum;
            double maxAxisYVal = ChartBase.ChartAreas[0].AxisY.Maximum;
            double minAxisYVal = ChartBase.ChartAreas[0].AxisY.Minimum;
            double axisXRange = maxAxisXVal - minAxisXVal;
            double axisYRange = maxAxisYVal - minAxisYVal;
            foreach (var item in SeriesCollection)
            {
                foreach (var point in item.Points)
                {
                    if (point.Visible)
                    {
                        if (point.Marker != null)
                        {
                            int test = 2;

                            listReturn.Add(new CircleRealPDF(point.Marker.MarkerSize, new ColorPDF(point.Marker.MarkerColor.R, point.Marker.MarkerColor.G, point.Marker.MarkerColor.B))
                            {
                                AutoIncrementYWritable = false,
                                DeltaX = X + (float)(point.Values.X - minAxisXVal) / (float)axisXRange * image.Width,
                                DeltaY = Y - ((float)(point.Values.Y - minAxisYVal) / (float)axisYRange * image.Height)
                            });

                        }
                    }
                }
            }
            // end of drawing custom markers

            #region Ritorno la Legenda

            if (ShowLegend)
            {
                // Aggiungo lo spazio del MarginAxisY e dell'altezza della Linea, marcatore e del testo dell'asse Y 
                listReturn.Add(new SpacePDF(10));

                var xLegenda = (X - 40) + LegendDeltaX;
                var tabellaLegenda = new TablePDF(xLegenda, SeriesCollection.Count * 3, 1)
                {
                    ID = "legend",
                    Footer = false,
                    Header = false,
                    PageBreak = false,
                    YOffset = _legendYOffset
                }; // *3 pari al numero di colonne di cui si compone la legenda (immagine, spazio, testo)

                var j = 0;
                foreach (var serie in SeriesCollection)
                {
                    if (serie.ShowInLegend)
                    {
                        tabellaLegenda.Columns.Add(new ColumnPDF("immagine" + j, LegendWidthColumns[0], HorizontalAlignmentType.Sinistra, false, false, LegendFontSizeText, ColumnType.Objectpdf));
                        tabellaLegenda.Columns.Add(new ColumnPDF("spazio" + j, LegendWidthColumns[1], HorizontalAlignmentType.Sinistra, false, false, LegendFontSizeText, ColumnType.Testo));
                        tabellaLegenda.Columns.Add(new ColumnPDF("testo" + j, LegendWidthColumns[2], HorizontalAlignmentType.Sinistra, false, false, LegendFontSizeText, ColumnType.Testo));

                        tabellaLegenda.Cells[j, 0].ValueObject = new RectanglePDF(LegendSymbolHeight, LegendWidthColumns[0], serie.Color) { AutoIncrementYWritable = false, DeltaY = LegendSymbolDeltaY };
                        tabellaLegenda.Cells[j + 1, 0].Value = string.Empty;
                        tabellaLegenda.Cells[j + 2, 0].Value = serie.Text;

                        j += 3;
                    }
                }

                listReturn.Add(tabellaLegenda);

                TotalHeight += 10; // +10 =  tabellaLegenda.Cells[j, 0].Height
            }

            #endregion


            Elements.AddRange(listReturn);

            return this;
        }
        private int MonthDifference(DateTime lValue, DateTime rValue)
        {
            return Math.Abs((lValue.Month - rValue.Month) + 12 * (lValue.Year - rValue.Year));
        }
        /// <summary>
        /// Crea il grafico di tipo StackedBar
        /// </summary>
        private void CreateChart()
        {
            var path = HttpContext.Current.Server.MapPath(".");

            ChartBase.AntiAliasing = AntiAliasing.All;
            ChartBase.TextAntiAliasingQuality = TextAntiAliasingQuality.High;

            // Disabilito il 3D
            ChartBase.ChartAreas[0].Area3DStyle.Enable3D = false;

            ChartBase.ChartAreas[0].BackColor = System.Drawing.Color.FromArgb(BackColor.Red, BackColor.Green, BackColor.Blue);
            ChartBase.ChartAreas[0].BorderColor = System.Drawing.Color.Empty;
            ChartBase.ChartAreas[0].BorderWidth = 0;

            ChartBase.ChartAreas[0].Position.Auto = true;
            ChartBase.ChartAreas[0].Position.X = 0;
            ChartBase.ChartAreas[0].Position.Y = 0;
            ChartBase.ChartAreas[0].Position.Width = 100;
            ChartBase.ChartAreas[0].Position.Height = 100;

            // Set the plotting area position. Coordinates of a plotting 
            // area are relative to a chart area position.
            ChartBase.ChartAreas[0].InnerPlotPosition.Auto = true;

            #region BackGroundImage

            if (!string.IsNullOrEmpty(BackImage))
            {
                ChartBase.ChartAreas[0].BackImage = string.Format(@"{0}\Images\{1}", path, BackImage);
                ChartBase.ChartAreas[0].BackImageMode = ChartImageWrapMode.Scaled;

            }
            #endregion

            #region Impostazioni Asse X

            switch (LabelFormatAxisX)
            {
                case FormatType.Data:
                case FormatType.DataShort:
                case FormatType.DataSenzaOra:

                    if (EqualDateLabelDistanceAxisX)
                    {
                        _minimumDate = DateTime.FromOADate(GetMinimunValueXPoints());
                        _maximumDate = DateTime.FromOADate(GetMaximumValueXPoints());
                        int monthsDifference = MonthDifference(_minimumDate, _maximumDate);
                        if (monthsDifference % IntervalNumberAxisX != 0)
                        {
                            _intervalMonths = (int)(monthsDifference / IntervalNumberAxisX) + 1;
                            monthsDifference = _intervalMonths * IntervalNumberAxisX;
                            _intervalDays = _intervalMonths * 30;
                        }
                        else
                        {
                            _intervalMonths = (int)(monthsDifference / IntervalNumberAxisX);
                        }
                        DateTime tmp = _minimumDate.AddMonths(monthsDifference);
                        _maximumDate = new DateTime(tmp.Year, tmp.Month, 1).AddMonths(1).AddSeconds(-1);
                    }
                    else
                    {
                        _minimumDate = DateTime.FromOADate(GetMinimunValueXPoints());
                        _maximumDate = DateTime.FromOADate(GetMaximumValueXPoints());
                        // calcolo la differenza in giorni tra minDate e maxDate
                        var days = _maximumDate.Subtract(_minimumDate).Days;
                        _intervalDays = days / IntervalNumberAxisX;
                    }

                    ChartBase.ChartAreas[0].AxisX.IntervalType = DateTimeIntervalType.Days;
                    ChartBase.ChartAreas[0].AxisX.Interval = _intervalDays;

                    _minimumAxisX = _minimumDate.ToOADate();
                    _maximumAxisX = _maximumDate.ToOADate();

                    ChartBase.ChartAreas[0].AxisX.Maximum = AxisXMaximum ?? _maximumAxisX;
                    ChartBase.ChartAreas[0].AxisX.Minimum = AxisXMinimum ?? _minimumAxisX;
                    //_intervalX = Helper.Round(_intervalDays); issue 3908
                    _intervalX = _intervalDays; // nei grafici con date sull'asse x è richiesto di non arrotondare per avere le date impostate ai valori min e max 
                                                // ChartBase.ChartAreas[0].AxisX.LabelsAutoFitStyle = LabelsAutoFitStyle.LabelsAngleStep30;
                                                // ChartBase.ChartAreas[0].AxisX.LabelStyle.FontAngle = -45;
                    break;
                default:
                    _maximumAxisX = MaximumValueAxisX != 0 ? MaximumValueAxisX : Helper.Round(GetMaximumValueXPoints());

                    _minimumAxisX = StartFromZeroAxisX ? 0 : Helper.Round(GetMinimunValueXPoints());

                    _intervalX = MaximumValueAxisX != 0 ? _maximumAxisX / IntervalNumberAxisX : Helper.Round(_maximumAxisX / IntervalNumberAxisX);
                    _maximumAxisX = _intervalX * IntervalNumberAxisX;

                    ChartBase.ChartAreas[0].AxisX.Maximum = _maximumAxisX;
                    ChartBase.ChartAreas[0].AxisX.Minimum = _minimumAxisX;
                    ChartBase.ChartAreas[0].AxisX.Interval = _intervalX;
                    break;
            }

            ChartBase.ChartAreas[0].AxisX.Margin = false;
            ChartBase.ChartAreas[0].AxisX.LabelStyle.Enabled = false;
            ChartBase.ChartAreas[0].AxisX.MajorGrid.Enabled = false;
            ChartBase.ChartAreas[0].AxisX.MinorTickMark.Enabled = false;
            ChartBase.ChartAreas[0].AxisX.MajorTickMark.Enabled = false;
            ChartBase.ChartAreas[0].AxisX.LineStyle = ChartDashStyle.NotSet;

            #endregion

            #region Impostazioni Asse Y

            if (DontCalculateMaxAndMinAxisY)
            {
                _maximumAxisY = MaximumValueAxisY;
                _minimumAxisY = MinimumValueAxisY;
                _intervalY = Math.Abs(MaximumValueAxisY - MinimumValueAxisY) / IntervalNumberAxisY;
            }
            else if(RemoveWhiteSpacesY)
            {
                //_maximumAxisY = Math.Truncate(GetMaximumValueYPoints() + 1);
                //_minimumAxisY = StartFromZeroAxisY ? 0 : Helper.Round(GetMinimumValueYPoints()) > 0 ? 0 : Helper.Round(GetMinimumValueYPoints());
                //_intervalY = _maximumAxisY / IntervalNumberAxisY;
                double tmpMaxValueY = GetMaximumValueYPoints();
                double tmpMinValueY = StartFromZeroAxisY ? 0 : GetMinimumValueYPoints();
                if (tmpMaxValueY == 0 && tmpMinValueY == 0)
                {
                    _maximumAxisY = 1;
                    _minimumAxisY = 0 + AxisYMinimumValueOffset;
                    _intervalY = (_maximumAxisY - _minimumAxisY) / IntervalNumberAxisY;
                }
                else
                {
                    double tmpDifference = Math.Abs(tmpMaxValueY - tmpMinValueY);
                    double tmpMinDifference = Math.Truncate(2 * tmpDifference / 100);

                    double tmpRoundedMin = StartFromZeroAxisY ? 0 : Helper.Round(GetMinimumValueYPoints(), true);
                    double tmpRoundedMax = Math.Truncate(Helper.Round(GetMaximumValueYPoints(), true));

                    if (Math.Abs(Math.Abs(tmpRoundedMin) - Math.Abs(tmpMinValueY)) < tmpMinDifference)
                    {
                        if (tmpRoundedMin < 0)
                        {
                            tmpRoundedMin -= tmpMinDifference;
                        }
                        else
                        {
                            tmpRoundedMin += tmpMinDifference;
                        }
                    }

                    if (Math.Abs(Math.Abs(tmpRoundedMax) - Math.Abs(tmpMaxValueY)) < tmpMinDifference)
                    {
                        if (tmpRoundedMin < 0)
                        {
                            tmpRoundedMax -= tmpMinDifference;
                        }
                        else
                        {
                            tmpRoundedMax += tmpMinDifference;
                        }
                    }
                    _maximumAxisY = tmpRoundedMax;
                    _minimumAxisY = tmpRoundedMin + AxisYMinimumValueOffset;
                    _intervalY = (_maximumAxisY - _minimumAxisY) / IntervalNumberAxisY;
                }
            }
            else
            {
                _maximumAxisY = MaximumValueAxisY != 0 ? MaximumValueAxisY : Helper.Round(GetMaximumValueYPoints());
                _minimumAxisY = StartFromZeroAxisY ? 0 : Helper.Round(GetMinimumValueYPoints()) > 0 ? 0 : Helper.Round(GetMinimumValueYPoints());
                _minimumAxisY += AxisYMinimumValueOffset;
                _intervalY = MaximumValueAxisY != 0 ? _maximumAxisY / IntervalNumberAxisY : Helper.Round((_maximumAxisY - _minimumAxisY) / IntervalNumberAxisY);
                if (_intervalY == 0)
                {
                    _intervalY++;
                }
                _maximumAxisY = _intervalY * IntervalNumberAxisY + (_minimumAxisY);


                //if (_minimumAxisY == _maximumAxisY && _minimumAxisY < 0)
                //{
                //    _maximumAxisY += 1;
                //    _intervalY = 1d / IntervalNumberAxisY;
                //}
                //else
                //{
                //    _intervalY = MaximumValueAxisY != 0 ? _maximumAxisY / IntervalNumberAxisY : Helper.Round((_maximumAxisY - _minimumAxisY) / IntervalNumberAxisY);
                //    _maximumAxisY = _intervalY * IntervalNumberAxisY + (_minimumAxisY);
                //}
            }

            ChartBase.ChartAreas[0].AxisY.Maximum = _maximumAxisY;
            ChartBase.ChartAreas[0].AxisY.Minimum = _minimumAxisY;
            ChartBase.ChartAreas[0].AxisY.Interval = _intervalY;

            ChartBase.ChartAreas[0].AxisY.Margin = false;
            ChartBase.ChartAreas[0].AxisY.LabelsAutoFit = true;
            ChartBase.ChartAreas[0].AxisY.LabelStyle.Enabled = false;

            ChartBase.ChartAreas[0].AxisY.MajorGrid.Enabled = false;
            ChartBase.ChartAreas[0].AxisY.MajorTickMark.Enabled = false;

            ChartBase.ChartAreas[0].AxisY.LineStyle = ChartDashStyle.NotSet;

            // MinorGrid

            if (MinorGridAxisY && !showZeroInLabel)
            {
                ChartBase.ChartAreas[0].AxisY.MinorGrid.Enabled = true;
                ChartBase.ChartAreas[0].AxisY.MinorGrid.LineStyle = ChartDashStyle.Dot;
                ChartBase.ChartAreas[0].AxisY.MinorGrid.Interval = ChartBase.ChartAreas[0].AxisY.Interval;

                ChartBase.ChartAreas[0].AxisY.MinorGrid.LineColor = System.Drawing.Color.Gray;
            }
            #endregion

            #region Impostazioni delle Serie
            int a = 0;
            foreach (var item in SeriesCollection)
            {
                // Imposto il nome della serie
                ChartBase.Series.Add(item.Name);

                // Imposto il tipo di grafico
                ChartBase.Series[item.Name].Type = item.Type;
                if (item.MarkerStyle != null)
                {
                    ChartBase.Series[item.Name].MarkerStyle = item.MarkerStyle ?? MarkerStyle.Circle;
                }

                if (item.MarkerSize != null)
                {
                    ChartBase.Series[item.Name].MarkerSize = item.MarkerSize ?? 5;
                }

                // Labelstyle
                if (!string.IsNullOrEmpty(item.LabelStyle))
                {
                    ChartBase.Series[item.Name]["LabelStyle"] = item.LabelStyle;
                }

                if (item.AutoCalculateLastPointLabelPosition)
                {
                    ChartBase.Series[item.Name]["LabelStyle"] = CalculateLabelPositionForLastPoint(item);
                }

                #region Personalizzazioni per tipo di Serie
                switch (item.Type)
                {
                    case SeriesChartType.Point:
                        // ChartBase.Series[item.Name].MarkerSize = 20;
                        //ChartBase.Series[item.Name].MarkerStyle = MarkerStyle.Circle;
                        //ChartBase.Series[item.Name].CustomAttributes = "LabelStyle=TopLeft";
                        ChartBase.Series[item.Name].ShadowOffset = 1;
                        ChartBase.Series[item.Name].FontColor = System.Drawing.Color.Black;
                        ChartBase.Series[item.Name].Font = new System.Drawing.Font("verdanab", 6F);


                        break;
                    case SeriesChartType.Area:
                        ChartBase.Series[item.Name].Color = System.Drawing.Color.FromArgb(item.Color.Red, item.Color.Green, item.Color.Blue);
                        break;
                }

                //MarkerImage
                if (!string.IsNullOrEmpty(item.MarkerImage))
                {
                    ChartBase.Series[item.Name].MarkerImage = string.Format(@"{0}\Images\{1}", path, item.MarkerImage);

                }

                #endregion

                #region Imposto il tipo di valori su asse X in funzione di LabelFormatType

                switch (LabelFormatAxisX)
                {
                    case FormatType.Data:
                    case FormatType.DataShort:
                    case FormatType.DataSenzaOra:
                        ChartBase.Series[item.Name].XValueType = ChartValueTypes.Date;
                        break;
                    default:
                        ChartBase.Series[item.Name].XValueType = ChartValueTypes.Auto;
                        break;
                }
                #endregion

                #region  Imposto il tipo di valori su asse Y in funzione di LabelFormatType

                switch (LabelFormatAxisY)
                {
                    case FormatType.Data:
                    case FormatType.DataShort:
                    case FormatType.DataSenzaOra:

                        ChartBase.Series[item.Name].YValueType = ChartValueTypes.Date;
                        break;
                    default:
                        ChartBase.Series[item.Name].YValueType = ChartValueTypes.Auto;
                        break;
                }
                #endregion

                //Imposto la larghezza delle barre di ciascuna Serie
                ChartBase.Series[item.Name]["PointWidth"] = item.PointWidth;

                #region Bordo

                // Bordo
                if (item.Border)
                {
                    ChartBase.Series[item.Name].BorderStyle = ChartDashStyle.Solid;
                    ChartBase.Series[item.Name].ShadowOffset = 4;
                }

                // BorderWidth
                ChartBase.Series[item.Name].BorderWidth = Convert.ToInt32(item.BorderWidth);
                // BorderStyle
                ChartBase.Series[item.Name].BorderStyle = item.BorderStyle;
                #endregion

                #region Aggiunta dei Points

                int i = 0;
                foreach (var point in item.Points)
                {
                    if (point.Visible)
                    {
                        ChartBase.Series[item.Name].Points.AddXY(point.Values.X, point.Values.Y);

                        ChartBase.Series[item.Name].Points[i].Color = System.Drawing.Color.FromArgb(point.Color.Red, point.Color.Green, point.Color.Blue);
                        ChartBase.Series[item.Name].Points[i].Label = point.Label;
                        ChartBase.Series[item.Name].Points[i].Font = point.Font;
                        //if (point.Marker != null)
                        //{
                        //    ChartBase.Series[item.Name].Points[i].MarkerStyle = point.Marker.MarkerStyle;
                        //    ChartBase.Series[item.Name].Points[i].MarkerSize = (int)point.Marker.MarkerSize;
                        //    ChartBase.Series[item.Name].Points[i].MarkerColor = point.Marker.MarkerColor;
                        //}
                        i++;
                    }
                }

                #endregion
                a++;
            }

            #endregion
        }

        #endregion
        private string CalculateLabelPositionForLastPoint(Serie serie)
        {
            if (serie.Points.Count == 0)
            {
                return "Auto";
            }
            double horizontalDiffToUseOwnAlgorithm = 0.12; // worst scenario string takes 20%
            double verticalDiffToUseOwnAlgorithm = 0.05;

            // for some reason, RendererPDF reverses entire collection, so we have to do the same (locally only)
            Point[] tmp = new Point[serie.Points.Count];
            serie.Points.CopyTo(tmp);
            List<Point> reversedPoints = tmp.ToList();
            reversedPoints.Reverse();

            double axisYMax = ChartBase.ChartAreas[0].AxisY.Maximum;
            double axisYMin = ChartBase.ChartAreas[0].AxisY.Minimum;
            double axisXMax = ChartBase.ChartAreas[0].AxisX.Maximum;
            double axisXMin = ChartBase.ChartAreas[0].AxisX.Minimum;

            double pointX = reversedPoints.Last().Values.X;
            double pointY = reversedPoints.Last().Values.Y;

            double xRange = axisXMax - axisXMin;
            double yRange = axisYMax - axisYMin;

            double distanceFromTop = axisYMax - pointY;
            double distanceFromBot = Math.Abs(axisYMin - pointY);
            double distanceFromLeft = Math.Abs(axisXMin - pointX);
            double distanceFromRight = axisXMax - pointX;

            double verticalDiffToUseAlgo = yRange * verticalDiffToUseOwnAlgorithm;
            double horizontalDiffToUseAlgo = xRange * horizontalDiffToUseOwnAlgorithm;

            bool tooCloseToTop = verticalDiffToUseAlgo > distanceFromTop;
            bool tooCloseToBot = verticalDiffToUseAlgo > distanceFromBot;
            bool tooCloseToLeft = horizontalDiffToUseAlgo > distanceFromLeft;
            bool tooCloseToRight = horizontalDiffToUseAlgo > distanceFromRight;

            // determining, what quater the point is in
            bool isOnTheLeftSide = true;
            bool isOnTheTopSide = false;

            if (pointX > axisXMin + xRange / 2)
            {
                isOnTheLeftSide = false;
            }
            if (pointY > axisYMin + yRange / 2)
            {
                isOnTheTopSide = true;
            }

            if (tooCloseToTop ||
                tooCloseToBot ||
                tooCloseToLeft ||
                tooCloseToRight)
            {
                if (tooCloseToTop)
                {
                    if (tooCloseToRight)
                    {
                        return "BottomLeft";
                    }
                    else
                    {
                        return "BottomRight";
                    }
                }
                else if (tooCloseToBot)
                {
                    if (tooCloseToRight)
                    {
                        return "TopLeft";
                    }
                    else
                    {
                        return "TopRight";
                    }
                }
                else if (tooCloseToLeft)
                {
                    if (isOnTheTopSide)
                    {
                        return "BottomRight";
                    }
                    else
                    {
                        return "TopRight";
                    }
                }
                else if (tooCloseToRight)
                {
                    if (isOnTheTopSide)
                    {
                        return "BottomLeft";
                    }
                    else
                    {
                        return "TopLeft";
                    }
                }                
            }
            else
            {
                return "Auto";
            }
            return "Auto";
        }
    }


    /// <summary>
    /// Struttura degli indicatori del grafico CombinationPDF. [Riquadro grigio con freccia].
    /// </summary>
    public struct CombinationPDFIndicator
    {
        public double Value { get; set; }
        public string Text { get; set; }
        public float DeltaX { get; set; }
        public float DeltaY { get; set; }
        public float DeltaYText { get; set; }
        public float DeltaXText { get; set; }
    }

    /// <summary>
    /// Struttura delle label personalizzate del grafico CombinationPDF.
    /// </summary>
    public struct CombinationPDFCustomLabel
    {
        public double Value { get; set; }
        public string Text { get; set; }
    }
}
