using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Printing;
namespace DevComponents.DotNetBar.Charts
{
    [ToolboxItem(false)]
    public class ChartPrint : PrintDocument
    {
        #region Private variables
        private ChartControl _ChartControl;
        private Image _ChartImage;
        private Rectangle _PrintBounds;
        private int _Columns;
        private int _Rows;
        private int _CurCell;
        private FitToPageScale _FitToPageScale = FitToPageScale.Normal;
        #endregion
        #region Constructors
        /// 
        /// ChartPrint
        /// 
        public ChartPrint()
            : base()
        {
        }
        /// 
        /// ChartPrint
        /// 
        /// ChartControl
        public ChartPrint(ChartControl chartControl)
            : base()
        {
            _ChartControl = chartControl;
        }
        /// 
        /// ChartPrint
        /// 
        /// ChartControl
        /// FitToPageScale
        public ChartPrint(ChartControl chartControl, FitToPageScale fitToPageScale)
            : base()
        {
            _ChartControl = chartControl;
            _FitToPageScale = fitToPageScale;
        }
        #endregion
        #region Public properties
        #region FitToPageScale
        /// 
        /// Gets or sets how the chart is scaled
        /// to fit the page when printing.
        /// 
        public FitToPageScale FitToPageScale
        {
            get { return (_FitToPageScale); }
            set { _FitToPageScale = value; }
        }
        #endregion
        #endregion
        #region OnBeginPrint
        protected override void OnBeginPrint(PrintEventArgs e)
        {
            base.OnBeginPrint(e);
            if (_ChartControl == null)
                throw new Exception("ChartControl has not been set.");
            Size size = _ChartControl.ClientSize;
            _PrintBounds = DefaultPageSettings.Bounds;
            Margins margins = DefaultPageSettings.Margins;
            _PrintBounds.X += margins.Left;
            _PrintBounds.Width -= (margins.Left + margins.Right);
            _PrintBounds.Y += margins.Top;
            _PrintBounds.Height -= (margins.Top + margins.Bottom);
            _Columns = (int)Math.Ceiling((double)size.Width / _PrintBounds.Width);
            _Rows = (int)Math.Ceiling((double)size.Height / _PrintBounds.Height);
            _CurCell = 0;
            _ChartImage = new Bitmap(size.Width, size.Height);
            using (Graphics g = Graphics.FromImage(_ChartImage))
                _ChartControl.PaintTo(g);
        }
        #endregion
        #region OnPrintPage
        protected override void OnPrintPage(PrintPageEventArgs e)
        {
            base.OnPrintPage(e);
            switch (FitToPageScale)
            {
                case Charts.FitToPageScale.Stretch:
                    PrintStretchPage(e);
                    break;
                case Charts.FitToPageScale.Zoom:
                    PrintZoomPage(e);
                    break;
                default:
                    PrintNormalPage(e);
                    break;
            }
        }
        #region PrintNormalPage
        private void PrintNormalPage(PrintPageEventArgs e)
        {
            Graphics g = e.Graphics;
            int curRow = _CurCell / _Columns;
            int curColumn = _CurCell % _Columns;
            int x = curColumn * _PrintBounds.Width;
            int y = curRow * _PrintBounds.Height;
            Rectangle rs = new Rectangle(x, y, _ChartImage.Width - x, _ChartImage.Height - y);
            Rectangle rd = new Rectangle(_PrintBounds.X, _PrintBounds.Y, _ChartImage.Width - x, _ChartImage.Height - y);
            Region saveClip = g.Clip;
            g.SetClip(_PrintBounds);
            g.DrawImage(_ChartImage, rd, rs, GraphicsUnit.Pixel);
            g.Clip = saveClip;
            _CurCell++;
            e.HasMorePages = (_CurCell < _Columns * _Rows);
        }
        #endregion
        #region PrintStretchPage
        private void PrintStretchPage(PrintPageEventArgs e)
        {
            Rectangle rs = new Rectangle(0, 0, _ChartImage.Width, _ChartImage.Height);
            e.Graphics.DrawImage(_ChartImage, _PrintBounds, rs, GraphicsUnit.Pixel);
            e.HasMorePages = false;
        }
        #endregion
        #region PrintZoomPage
        private void PrintZoomPage(PrintPageEventArgs e)
        {
            Rectangle rd = _PrintBounds;
            SizeF size = new SizeF(_ChartImage.Width / _ChartImage.HorizontalResolution,
                _ChartImage.Height / _ChartImage.VerticalResolution);
            float scale = Math.Min(rd.Width / size.Width, rd.Height / size.Height);
            size.Width *= scale;
            size.Height *= scale;
            e.Graphics.DrawImage(_ChartImage, rd.X, rd.Y, size.Width, size.Height);
            e.HasMorePages = false;
        }
        #endregion
        #endregion
        #region OnEndPrint
        protected override void OnEndPrint(PrintEventArgs e)
        {
            base.OnEndPrint(e);
            if (_ChartImage != null)
                _ChartImage.Dispose();
            _ChartImage = null;
        }
        #endregion
    }
    #region FitToPageScale
    public enum FitToPageScale
    {
        Normal,
        Stretch,
        Zoom,
    }
    #endregion
}