//------------------------------------------------------------------------------
// <copyright file=”*.cs” company=”EhLib Team”>
//     Copyright (c) 2017 Dmitry V. Bolshakov   
// </copyright>
//------------------------------------------------------------------------------

using System;
using System.Windows.Forms;
using System.Drawing;
using System.Security.Permissions;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows.Forms.VisualStyles;
using System.Drawing.Drawing2D;

namespace EhLib
{

  [ToolboxItem(false)]
  [DesignerCategory("Code")]
  public class BaseGridHorzScrollBarControl : HScrollBar
  {
    public BaseGridHorzScrollBarControl()
    {
    }

    protected override void WndProc(ref Message m)
    {
      switch (m.Msg)
      {
        case NativeMethods.WM_LBUTTONDOWN:
          WmMouseDown();
          break;
      }
      base.WndProc(ref m);
    }

    private void WmMouseDown()
    {
      BaseGridControl grid = ((BaseGridScrollBarPanelControl) Parent).Grid;
      if ((grid != null) && (grid.CanFocus) && (!grid.ContainsFocus))
        grid.FocusGrid();
    }
  }

  [ToolboxItem(false)]
  [DesignerCategory("Code")]
  public class BaseGridVertScrollBarControl : VScrollBar
  {
    public BaseGridVertScrollBarControl()
    {
      //SetStyle(ControlStyles.UserMouse, true);
      //SetStyle(ControlStyles.Selectable, false);
    }

    protected override void WndProc(ref Message m)
    {
      switch (m.Msg)
      {
        case NativeMethods.WM_LBUTTONDOWN:
          WmMouseDown();
          break;
      }
      base.WndProc(ref m);
    }

    private void WmMouseDown()
    {
      BaseGridControl grid = ((BaseGridScrollBarPanelControl) Parent).Grid;
      if ((grid != null) && (grid.CanFocus) && (!grid.ContainsFocus))
        grid.FocusGrid();
    }
  }

  [ToolboxItem(false)]
  [DesignerCategory("Code")]
  public class BaseGridScrollBarPanelControl : Control
  {

    #region privates
    private readonly ScrollBar scrollBar;
    private bool keepMaxSizeInDefault;
    private readonly BaseGridControl grid;
    private readonly Orientation kind;
    private bool backColorStored;

    #endregion privates

    //Constructor  Create( AOwner,  AKind)
    public BaseGridScrollBarPanelControl(BaseGridControl grid, Orientation kind)
    {

      this.SetStyle(ControlStyles.Selectable, false);
      //TabStop = false;

      this.kind = kind;
      this.grid = grid;
      if (this.Kind == Orientation.Horizontal)
        scrollBar = new BaseGridHorzScrollBarControl();
      else
        scrollBar = new BaseGridVertScrollBarControl();
      scrollBar.Parent = this;
      scrollBar.Scroll += HandleScroll;
      scrollBar.TabStop = false;

      Controls.Add(scrollBar);
      keepMaxSizeInDefault = true;
      //BackColor = SystemColors.Control;
    }

    #region Properties
    public override Color BackColor
    {
      get
      {
        if (this.ShouldSerializeBackColor())
          return base.BackColor;
        else
          return SystemColors.Control;
      }
      set
      {
        if (BackColor != value)
        {
          backColorStored = true;
          base.BackColor = value;
        }
      }
    }

    public Orientation Kind
    {
      get { return kind; }
    }

    public BaseGridControl Grid
    {
      get { return grid; }
    }

    public ScrollBar ScrollBar
    {
      get { return scrollBar; }
    }

    public bool KeepMaxSizeInDefault
    {
      get { return keepMaxSizeInDefault; }
      set { SetKeepMaxSizeInDefault(value); }
    }

    #endregion

    #region Methods
    private bool ShouldSerializeBackColor()
    {
      return backColorStored;
    }

    public override void ResetBackColor()
    {
      backColorStored = false;
      Invalidate();
    }

    protected override void OnLayout(LayoutEventArgs levent)
    {
      base.OnLayout(levent);
      RealignControls();
    }

    public virtual bool ChildControlCanMouseDown(Control control)
    {
      //      result = Grid.ChildControlCanMouseDown(AControl);
      return false;
    }

    public int MaxSizeForExtraPanel()
    {
      int result = this.Width - 14;
      return result;
    }

    protected void HandleScroll(object sender, ScrollEventArgs e)
    {
      Grid.ScrollBarMessage(Kind, e, false);
    }

    private void SetKeepMaxSizeInDefault(bool value)
    {
      //if (keepMaxSizeInDefault != value)
      //{
      keepMaxSizeInDefault = value;
        //        this.Realign;
      //}
    }

    public void SetParams(int position, int min, int max, int pageSize)
    {
      if (scrollBar.LargeChange > max)
      {
        scrollBar.LargeChange = 0;
      }
      if (min > max)
      {
        max = min;
      }
      scrollBar.Minimum = min;
      scrollBar.Maximum = max;
      scrollBar.Value = position;
      scrollBar.LargeChange = pageSize;
      if ((max <= min) || (max - min < pageSize))
        scrollBar.Enabled = false;
      else
        scrollBar.Enabled = true;
    }

    public virtual void RealignControls()
    {
      int newWidth;
      int newHeight;

      //if (!IsHandleCreated) return;

      if (Kind == Orientation.Horizontal)
      {
        newWidth = this.Width;
        newHeight = Grid.HorzScrollBar.ActualScrollBarBoxSize();
      }
      else
      {
        newWidth = Grid.VertScrollBar.ActualScrollBarBoxSize();
        newHeight = this.Height;
      }
      scrollBar.SetBounds(this.Width - newWidth, this.Height - newHeight, newWidth, newHeight);
    }

    public void ResetBounds(int x, int y, int width, int height)
    {
      if (Bounds == new Rectangle(x, y, width, height))
        RealignControls();
      else
        SetBounds(x, y, width, height);
    }

    #endregion Methods

  }

  [ToolboxItem(false)]
  public class SizeGripControl : Panel
  {

    #region privates
    private const int SizeGripSize = 16;

    private bool triangleWindow = true;
    private GripActiveStatus gripActiveStatus;
    private SizeGripPosition position = SizeGripPosition.BottomRight;
    private Point initFormSize;
    private Point initFormPos;
    private Point screenMousePos;
    private VisualStyleRenderer sizeGripRenderer;
    private bool backColorStored;
    private Form lowForm;
    #endregion privates

    #region properties
    protected override Cursor DefaultCursor
    {
      get
      {
        if (CheckGripActive())
        {
          switch (Position)
          {
            case SizeGripPosition.BottomRight:
            case SizeGripPosition.TopLeft:
              return Cursors.SizeNWSE;
            case SizeGripPosition.TopRight:
            case SizeGripPosition.BottomLeft:
              return Cursors.SizeNESW;
            default:
              return Cursors.Default;
          }
        }
        else
          return Cursors.Default;
      }
    }

    public bool TriangleWindow
    {
      get
      {
        return triangleWindow;
      }

      set
      {
        if (value != triangleWindow)
        {
          triangleWindow = value;
          UpdateWindowRegion();
        }
      }
    }

    public GripActiveStatus GripActiveStatus
    {
      get
      {
        return gripActiveStatus;
      }

      set
      {
        gripActiveStatus = value;
      }
    }

    public SizeGripPosition Position
    {
      get
      {
        return position;
      }

      set
      {
        SetPosition(value);
      }
    }
    #endregion properties

    public SizeGripControl()
    {
      //BackColor = SystemColors.Control;
    }

    public override Color BackColor
    {
      get
      {
        if (this.ShouldSerializeBackColor())
          return base.BackColor;
        else
          return SystemColors.Control;
      }
      set
      {
        if (BackColor != value)
        {
          backColorStored = true;
          base.BackColor = value;
        }
      }
    }

    #region methods
    private bool ShouldSerializeBackColor()
    {
      return backColorStored;
    }

    public override void ResetBackColor()
    {
      backColorStored = false;
      Invalidate();
    }

    protected bool CheckInCorner()
    {
      bool result = false;
      Point point1;
      Point point2;
      Form form = FindForm();

      if (form != null)
      {
        if ((form.FormBorderStyle == FormBorderStyle.Sizable) ||
            (form.FormBorderStyle == FormBorderStyle.SizableToolWindow))
        {
          point1 = PointToScreen(new Point(Width, Height));
          point2 = form.PointToScreen(new Point(form.ClientSize));

          if ((Math.Abs(point2.X - point1.X) < 4) && (Math.Abs(point2.Y - point1.Y) < 4))
            result = true;
        }
      }
      return result;
    }

    protected bool CheckGripActive()
    {
      bool result;
      if (GripActiveStatus == GripActiveStatus.Never)
        result = false;
      else if (GripActiveStatus == GripActiveStatus.Auto)
        result = CheckInCorner();
      else
        result = true;
      return result;
    }

    protected override void OnHandleCreated(EventArgs e)
    {
      base.OnHandleCreated(e);
      UpdateWindowRegion();
      this.Invalidate();
    }

    protected override void OnResize(EventArgs e)
    {
      base.OnResize(e);
    }

    protected Point GetFormSize()
    {
      return new Point(-1, -1);
    }

    protected override void OnMouseDown(MouseEventArgs e)
    {
      base.OnMouseDown(e);
      if (this.Capture && CheckGripActive())
      {
        lowForm = FindLowForm();
        Debug.Assert(lowForm != null, "form != null");
        initFormSize = new Point(lowForm.Width, lowForm.Height);
        initFormPos = new Point(lowForm.Left, lowForm.Top);
        screenMousePos = this.PointToScreen(new Point(e.X, e.Y));
      }
    }

    protected override void OnMouseMove(MouseEventArgs e)
    {
      Point newMousePos;
      int newLeft;
      int newTop;
      int newWidth;
      int newHeight;

      base.OnMouseMove(e);
      if (this.Capture && !((screenMousePos.X == -1) && (screenMousePos.Y == -1)))
      {
        newMousePos = this.PointToScreen(new Point(e.X, e.Y));
        if ((newMousePos.X != screenMousePos.X) || (newMousePos.Y != screenMousePos.Y))
        {
          if (Position == SizeGripPosition.TopLeft)
          {
            newWidth = initFormSize.X - (newMousePos.X - screenMousePos.X);
            newHeight = initFormSize.Y - (newMousePos.Y - screenMousePos.Y);
            newLeft = initFormPos.X + initFormSize.X - newWidth;
            newTop = initFormPos.Y + initFormSize.Y - newHeight;
          }
          else if (Position == SizeGripPosition.TopRight)
          {
            newWidth = initFormSize.X + (newMousePos.X - screenMousePos.X);
            newHeight = initFormSize.Y - (newMousePos.Y - screenMousePos.Y);
            newLeft = initFormPos.X;
            newTop = initFormPos.Y + initFormSize.Y - newHeight;
          }
          else if (Position == SizeGripPosition.BottomRight)
          {
            newWidth = initFormSize.X + (newMousePos.X - screenMousePos.X);
            newHeight = initFormSize.Y + (newMousePos.Y - screenMousePos.Y);
            newLeft = initFormPos.X;
            newTop = initFormPos.Y;
          }
          else
          {
            newWidth = initFormSize.X - (newMousePos.X - screenMousePos.X);
            newHeight = initFormSize.Y + (newMousePos.Y - screenMousePos.Y);
            newLeft = initFormPos.X + initFormSize.X - newWidth;
            newTop = initFormPos.Y;
          }
          Debug.Assert(lowForm != null, "form != null");
          lowForm.SetBounds(newLeft, newTop, newWidth, newHeight);
          lowForm.Refresh();
        }
      }
    }

    protected override void OnMouseUp(MouseEventArgs e)
    {
      base.OnMouseUp(e);
      screenMousePos = new Point(-1, -1);
    }

    protected void SetCursor()
    {
      //if (CheckGripActive())
      //{
      //  switch (Position)
      //  {
      //    case SizeGripPosition.BottomRight:
      //    case SizeGripPosition.TopLeft:
      //      Cursor = Cursors.SizeNWSE;
      //      return;
      //    case SizeGripPosition.TopRight:
      //    case SizeGripPosition.BottomLeft:
      //      Cursor = Cursors.SizeNESW;
      //      return;
      //  }
      //}
      //else
      //  Cursor = Cursors.Default;
    }

    public void Paint_UpendDraw()
    {
    }

    public void Paint_RestoreDraw()
    {
    }

    protected override void OnPaint(PaintEventArgs e)
    {
      if (!CheckGripActive()) return;

      Size sz = ClientSize;
      Rectangle paintRect = new Rectangle(sz.Width - SizeGripSize, sz.Height - SizeGripSize, SizeGripSize, SizeGripSize);

      using (Bitmap bmFlipBm = new Bitmap(paintRect.Width, paintRect.Height))
      {
        using (Graphics gFlip = Graphics.FromImage(bmFlipBm))
        {
          //render.DrawBackground(gFlip, ClientRectangle);
          Rectangle bmFlipRect = new Rectangle(Point.Empty, bmFlipBm.Size);
          DrawGripRenderer(gFlip, bmFlipRect);

          switch (Position)
          {
            case SizeGripPosition.BottomRight:
              paintRect = new Rectangle(sz.Width - SizeGripSize, sz.Height - SizeGripSize, SizeGripSize, SizeGripSize);
              break;
            case SizeGripPosition.TopRight:
              bmFlipBm.RotateFlip(RotateFlipType.RotateNoneFlipY);
              paintRect = new Rectangle(sz.Width - SizeGripSize, 0, SizeGripSize, SizeGripSize);
              break;
          }

          e.Graphics.DrawImage(bmFlipBm, paintRect, bmFlipRect, GraphicsUnit.Pixel);
        }
      }
    }

    private void DrawGripRenderer(Graphics graphics, Rectangle rect)
    {
      if (Application.RenderWithVisualStyles)
      {
        if (sizeGripRenderer == null)
        {
          sizeGripRenderer = new VisualStyleRenderer(VisualStyleElement.Status.Gripper.Normal);
        }

        sizeGripRenderer.DrawBackground(graphics, rect);
      }
      else
      {
        ControlPaint.DrawSizeGrip(graphics, BackColor, rect.Left, rect.Top, rect.Width, rect.Height);
      }
    }

    public void UpdateWindowRegion()
    {
      Point[] points = new Point[3];

      if (TriangleWindow)
      {
        if (Position == SizeGripPosition.BottomRight)
        {
          points[0] = new Point(0, Height);
          points[1] = new Point(Width, Height);
          points[2] = new Point(Width, 0);
        }
        else if (Position == SizeGripPosition.BottomLeft)
        {
          points[0] = new Point(Width, Height);
          points[1] = new Point(0, Height);
          points[2] = new Point(0, 0);
        }
        else if (Position == SizeGripPosition.TopLeft)
        {
          points[0] = new Point(Width - 1, 0);
          points[1] = new Point(0, 0);
          points[2] = new Point(0, Height - 1);
        }
        else if (Position == SizeGripPosition.TopRight)
        {
          points[0] = new Point(Width, Height - 1);
          points[1] = new Point(Width, 0);
          points[2] = new Point(1, 0);
        }

        using (var path = new GraphicsPath())
        {
          path.AddPolygon(points);
          Region = new Region(path);
        }
      }
      else
      {
        Region = null;
      }

      SetCursor();
    }

    public void SetPosition(SizeGripPosition value)
    {
      if (position != value)
      {
        position = value;
        UpdateWindowRegion();
      }
    }

    public Form FindLowForm()
    {
      Form form = FindForm();
      if (form != null && form.MdiParent != null)
        form = form.MdiParent;
      return form;
    }

    #endregion methods
  }

  public class GridDragWin : Form
  {
    //private const int WS_EX_TOPMOST = 0x00000008;

    //private Color _fTransparentColorValue = Color.Empty;
    private bool backColorStored;

    public GridDragWin()
    {
      FormBorderStyle = FormBorderStyle.None;
      //TransparencyKey = Color.Black;
      ShowInTaskbar = false;
      //BackColor = Color.Black;
    }

    public override Color BackColor
    {
      get
      {
        if (ShouldSerializeBackColor())
          return base.BackColor;
        else
          return Color.Black;
      }
      set
      {
        if (BackColor != value)
        {
          backColorStored = true;
          base.BackColor = value;
        }
      }
    }

    protected override bool ShowWithoutActivation
    {
      get { return true; }
    }

//    [EnvironmentPermissionAttribute(SecurityAction.LinkDemand, Unrestricted = true)]
    protected override void DefWndProc(ref Message m)
    {
      //const int WM_MOUSEACTIVATE = 0x21;
      //const int MA_NOACTIVATE = 0x0003;

      switch (m.Msg)
      {
        case NativeMethods.WM_MOUSEACTIVATE:
          m.Result = (IntPtr)NativeMethods.MA_NOACTIVATE;
          return;
      }
      base.DefWndProc(ref m);
    }

    protected override CreateParams CreateParams
    {
      //[EnvironmentPermissionAttribute(SecurityAction.LinkDemand, Unrestricted = true)]
      get
      {
        CreateParams baseParams = base.CreateParams;
        baseParams.ExStyle |= NativeMethods.WS_EX_TOPMOST;
        return baseParams;
      }
    }

    #region Methods
    private bool ShouldSerializeBackColor()
    {
      return backColorStored;
    }

    public override void ResetBackColor()
    {
      backColorStored = false;
      Invalidate();
    }

    public void MoveToFor(Control control, Point newPos)
    {
      Point absPos = control.PointToScreen(newPos);
      SetBounds(absPos.X, absPos.Y, Width, Height);
    }

    public void StartShow(Control control, Point pos, int width, int height)
    {
      Point absPos = control.PointToScreen(pos);
      //Debug.WriteLine(Control.ToString() + " - " + AbsPos.ToString());
      Show();
      SetBounds(absPos.X, absPos.Y, width, height);
    }

    public void TemporaryHide()
    {
    }
    #endregion

  }

  public class GridMoveLine : GridDragWin
  {

    private static GridMoveLine _moveLine;
    private bool isVert;

    public GridMoveLine()
    {
      TransparencyKey = Color.Black;
    }

    public static GridMoveLine GetMoveLine()
    {
      if (_moveLine == null)
      {
        _moveLine = new GridMoveLine();
      }
      return _moveLine;
    }

    public bool IsVert
    {
      get { return isVert; }
    }

    protected override void OnPaint(PaintEventArgs e)
    {
      using (Pen pen = new Pen(Color.Red))
      {
        e.Graphics.DrawLine(pen, new Point(0, 0), new Point(6, 0));
        e.Graphics.DrawLine(pen, new Point(1, 1), new Point(5, 1));
        e.Graphics.DrawLine(pen, new Point(2, 2), new Point(4, 2));

        e.Graphics.DrawLine(pen, new Point(3, 3), new Point(3, Height - 4));

        e.Graphics.DrawLine(pen, new Point(2, Height - 3), new Point(4, Height - 3));
        e.Graphics.DrawLine(pen, new Point(1, Height - 2), new Point(5, Height - 2));
        e.Graphics.DrawLine(pen, new Point(0, Height - 1), new Point(6, Height - 1));
      }
    }

    public void StartShow(Control control, Point pos, bool isVert, int size, object captureControl)
    {
      this.isVert = isVert;
      UpdateOrientationData();
      pos.X = pos.X - 3;
      pos.Y = pos.Y - 4;
      size = size + 8;
      if (IsVert)
        base.StartShow(control, pos, 7, size);
      else
        base.StartShow(control, pos, size, 7);
    }

    public new void MoveToFor(Control control, Point newPos)
    {
      newPos.X = newPos.X - 3;
      newPos.Y = newPos.Y - 4;
      base.MoveToFor(control, newPos);
    }

    public void UpdateOrientationData()
    {

    }

  }

  public class MovePoint : GridMoveLine
  {
    public Color BackPaintColor;
    public Color ForePaintColor;
    public Color LineColor;

    protected override void OnPaint(PaintEventArgs e)
    {
      using (Pen pen = new Pen(ForePaintColor))
      {
        e.Graphics.DrawLine(pen, new Point(0, 0), new Point(6, 0));
        e.Graphics.DrawLine(pen, new Point(1, 1), new Point(5, 1));
        e.Graphics.DrawLine(pen, new Point(2, 2), new Point(4, 2));
        e.Graphics.DrawLine(pen, new Point(3, 2), new Point(3, 3));

      }

      using (Pen pen = new Pen(BackPaintColor))
      {
        e.Graphics.DrawLine(pen, new Point(2, 0), new Point(4, 0));
        e.Graphics.DrawLine(pen, new Point(3, 0), new Point(3, 1));
      }

      using (Pen pen = new Pen(LineColor))
      {
        e.Graphics.DrawLine(pen, new Point(3, 4), new Point(3, Height));
      }
    }
  }

  [TypeConverter(typeof(ExpandableObjectConverter))]
  public class GridBackground
  {
    #region privates
    private readonly BaseGridControl grid;
    private Image image;
    private readonly GridOpacityOptions gridOpacityOptions;
    private readonly GridBackgroundImageOptions imageOptions;
    private bool visible;
    #endregion

    #region constructor
    public GridBackground(BaseGridControl grid)
    {
      this.grid = grid;
      this.gridOpacityOptions = new GridOpacityOptions(this);
      this.imageOptions = new GridBackgroundImageOptions(this);
    }
    #endregion

    #region properties
    [Browsable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public BaseGridControl Grid
    {
      get { return grid; }
    }

    [DefaultValue(null)]
    [Localizable(true)]
    public virtual Image Image
    {
      get
      {
        return image;
      }

      set
      {
        if (Image != value)
        {
          image = value;
          grid.GridBackgroundChanged();
        }
      }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public GridBackgroundImageOptions ImageOptions
    {
      get { return imageOptions; }
    }

    [DefaultValue(false)]
    public bool Visible
    {
      get
      {
        return visible;
      }

      set
      {
        if (visible != value)
        {
          visible = value;
          grid.GridBackgroundChanged();
        }
      }
    }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public GridOpacityOptions GridOpacityOptions
    {
      get { return gridOpacityOptions; }
    }

    #endregion

    #region methods

    //Other
    internal void GridOpacityOptionsChagned()
    {
      Grid.GridBackgroundChanged();
    }

    internal virtual void OnPaint(PaintEventArgs e)
    {

      // TODO: Postpone. Implement the Layout property functional.

      using (SolidBrush brush = new SolidBrush(grid.BackColor))
      {
        e.Graphics.FillRectangle(brush, e.ClipRectangle);
      }

      if (Image == null) return;

      Rectangle imageBaseRect = new Rectangle(0, 0, Image.Width, Image.Height);
      Rectangle imageRect = imageBaseRect;

      imageRect.Width = (int)Math.Round(imageRect.Width * ImageOptions.Scale);
      imageRect.Height = (int)Math.Round(imageRect.Height * ImageOptions.Scale);

      imageRect.X = grid.HorzAxis.ContraStart - imageRect.Width - ImageOptions.Padding.Right;
      imageRect.Y = grid.VertAxis.ContraStart - imageRect.Height - ImageOptions.Padding.Bottom;

      EhLibUtils.DrawImage(e.Graphics, Image, imageRect, imageBaseRect, ImageOptions.Opacity, false);
    }  
    #endregion


    internal void ImageOptionsChanged()
    {
      GridOpacityOptionsChagned();
    }
  }

  [TypeConverter(typeof(ExpandableObjectConverter))]
  public class GridOpacityOptions
  {
    readonly GridBackground background;
    private int focusCellOpacity = 255;
    private int cellsOpacity = 255;
    private int linesOpacity = 255;

    #region constructor
    public GridOpacityOptions(GridBackground background)
    {
      this.background = background;
    }
    #endregion
    
    [DefaultValue(255)]
    public int FocusCellOpacity
    {
      get
      {
        return focusCellOpacity;
      }

      set
      {
        if (focusCellOpacity != value)
        {
          focusCellOpacity = value;
          background.GridOpacityOptionsChagned();
        }
      }
    }

    [DefaultValue(255)]
    public int CellsOpacity
    {
      get
      {
        return cellsOpacity;
      }

      set
      {
        if (CellsOpacity != value)
        {
          cellsOpacity = value;
          background.GridOpacityOptionsChagned();
        }
      }
    }

    [DefaultValue(255)]
    public int LinesOpacity
    {
      get
      {
        return linesOpacity;
      }

      set
      {
        if (linesOpacity != value)
        {
          linesOpacity = value;
          background.GridOpacityOptionsChagned();
        }
      }
    }
  }

  [TypeConverter(typeof(ExpandableObjectConverter))]
  public class GridBackgroundImageOptions
  {
    private readonly GridBackground background;
    private ImageLayout layout = ImageLayout.Tile;
    private int opacity = 255;
    private double scale = 1.0f;
    private Padding padding = Padding.Empty;
    private bool paddingStored;

    #region constructor
    public GridBackgroundImageOptions(GridBackground background)
    {
      this.background = background;
    }
    #endregion

    [DefaultValue(ImageLayout.Tile)]
    [Localizable(true)]
    public virtual ImageLayout Layout
    {
      get
      {
        return layout;
      }

      set
      {
        if (Layout != value)
        {
          layout = value;
          background.ImageOptionsChanged();
        }
      }
    }

    [DefaultValue(255)]
    public int Opacity
    {
      get
      {
        return opacity;
      }

      set
      {
        if (opacity != value)
        {
          opacity = value;
          background.ImageOptionsChanged();
        }
      }
    }

    [DefaultValue(1.0)]
    public double Scale
    {
      get
      {
        return scale;
      }

      set
      {
        if (scale != value)
        {
          scale = value;
          background.ImageOptionsChanged();
        }
      }
    }

    public Padding Padding
    {
      get
      {
        if (paddingStored)
          return padding;
        else
          return DefaultPadding();
      }

      set
      {
        padding = value;
        paddingStored = true;
        PaddingChanged();
      }
    }

    //Padding
    public virtual void PaddingChanged()
    {
      background.ImageOptionsChanged();
    }

    public virtual Padding DefaultPadding()
    {
      return Padding.Empty;
    }

    public virtual bool ShouldSerializePadding()
    {
      return (paddingStored == true);
    }

    public virtual void ResetPadding()
    {
      paddingStored = false;
      PaddingChanged();
    }
  }

}

