/*
 * NPlot - A charting library for .NET
 * 
 * Marker.cs
 * Copyright (C) 2003-2006 Matt Howlett and others.
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of NPlot nor the names of its contributors may
 *    be used to endorse or promote products derived from this software without
 *    specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

using System;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace NPlot
{

	/// <summary>
	/// Encapsulates functionality relating to markers used by the PointPlot class.
	/// </summary>
	public class Marker
	{

		/// <summary>
		/// Enumeration of all different types of marker.
		/// </summary>
		public enum MarkerType
		{
			/// <summary>
			/// A simple cross marker (x).
			/// </summary>
			Cross1,
			/// <summary>
			/// Another simple cross marker (+).
			/// </summary>
			Cross2,
			/// <summary>
			/// A circle marker.
			/// </summary>
			Circle,
			/// <summary>
			/// A square marker.
			/// </summary>
			Square,
			/// <summary>
			/// A triangle marker (upwards).
			/// </summary>
			Triangle,
			/// <summary>
			/// A triangle marker (upwards).
			/// </summary>
			TriangleUp,
			/// <summary>
			/// A triangle marker (upwards).
			/// </summary>
			TriangleDown,
			/// <summary>
			/// A diamond,
			/// </summary>
			Diamond,
			/// <summary>
			/// A filled circle
			/// </summary>
			FilledCircle,
			/// <summary>
			/// A filled square
			/// </summary>
			FilledSquare,
			/// <summary>
			/// A filled triangle
			/// </summary>
			FilledTriangle,
			/// <summary>
			/// A small flag (up)
			/// </summary>
			Flag,
			/// <summary>
			/// A small flag (up)
			/// </summary>
			FlagUp,
			/// <summary>
			/// A small flag (down)
			/// </summary>
			FlagDown,
			/// <summary>
			/// No marker
			/// </summary>
			None
		}

		private MarkerType markerType_;
		private int size_;
		private int h_;
		private System.Drawing.Pen pen_ = new Pen( Color.Black );
		private System.Drawing.Brush brush_ = new SolidBrush( Color.Black );
		private bool filled_ = false;
		private bool dropLine_ = false;


		/// <summary>
		/// The type of marker.
		/// </summary>
		public MarkerType Type
		{
			get
			{
				return markerType_;
			}
			set
			{
				markerType_ = value;
			}
		}


		/// <summary>
		/// Whether or not to draw a dropline.
		/// </summary>
		public bool DropLine
		{
			get
			{
				return dropLine_;
			}
			set
			{
				dropLine_ = value;
			}
		}


        /// <summary>
		/// The marker size.
		/// </summary>
		public int Size
		{
			get
			{
				return size_;
			}
			set
			{
				size_ = value;
				h_ = size_/2;
			}
		}


		/// <summary>
		/// The brush used to fill the marker.
		/// </summary>
		public Brush FillBrush
		{
			get
			{
				return brush_;
			}
			set
			{
				brush_ = value;
			}
		}


		/// <summary>
		/// Fill with color.
		/// </summary>
		public bool Filled
		{
			get
			{
				return filled_;
			}
			set
			{
				filled_ = value;
			}
		}


		/// <summary>
		/// Sets the pen color and fill brush to be solid with the specified color.
		/// </summary>
		public System.Drawing.Color Color
		{
			set
			{
				pen_.Color = value;
				brush_ = new SolidBrush( value );
			}
			get
			{
				return pen_.Color;
			}
		}


		/// <summary>
		/// The Pen used to draw the marker.
		/// </summary>
		public System.Drawing.Pen Pen
		{
			set
			{
				pen_ = value;
			}
			get
			{
				return pen_;
			}
		}


		/// <summary>
		/// Default constructor.
		/// </summary>
		public Marker()
		{
			markerType_ = MarkerType.Square;
			Size = 4;
			filled_ = false;
		}


		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="markertype">The marker type.</param>
		public Marker( MarkerType markertype )
		{
			markerType_ = markertype;
			Size = 4;
			filled_ = false;
		}

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="markertype">The marker type.</param>
		/// <param name="size">The marker size.</param>
		public Marker( MarkerType markertype, int size )
		{
			markerType_ = markertype;
			Size = size;
			filled_ = false;
		}


		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="markertype">The marker type.</param>
		/// <param name="size">The marker size.</param>
		/// <param name="color">The marker color.</param>
		public Marker( MarkerType markertype, int size, Color color )
		{
			markerType_ = markertype;
			Size = size;
			Color = color;
			filled_ = false;
		}


		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="markertype">The marker type.</param>
		/// <param name="size">The marker size.</param>
		/// <param name="pen">The marker Pen.</param>
		public Marker( MarkerType markertype, int size, Pen pen )
		{
			markerType_ = markertype;
			Size = size;
			Pen = pen;
			filled_ = false;
		}


		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="markertype">The marker type.</param>
		/// <param name="size">The marker size.</param>
		/// <param name="pen">The marker Pen.</param>
		/// <param name="fill">The fill flag.</param>
		public Marker( MarkerType markertype, int size, Pen pen, bool fill )
		{
			markerType_ = markertype;
			Size = size;
			Pen = pen;
			filled_ = fill;
		}



		/// <summary>
		/// Draws the marker at the given position
		/// </summary>
		/// <param name="g">The graphics surface on which to draw.</param>
		/// <param name="x">The [physical] x position to draw the marker.</param>
		/// <param name="y">The [physical] y position to draw the marker.</param>
		public void Draw( Graphics g, int x, int y )
		{

			switch (markerType_)
			{

				case MarkerType.Cross1:
					g.DrawLine( pen_, x-h_, y+h_, x+h_, y-h_ );
					g.DrawLine( pen_, x+h_, y+h_, x-h_, y-h_ );
					break;

				case MarkerType.Cross2:
					g.DrawLine( pen_, x, y-h_, x, y+h_ );
					g.DrawLine( pen_, x-h_, y, x+h_, y );
					break;

				case MarkerType.Circle:
					g.DrawEllipse( pen_, x-h_, y-h_, size_, size_ );
					if ( this.filled_ ) 
					{
						g.FillEllipse( brush_, x-h_, y-h_, size_, size_ );
					}
					break;

				case MarkerType.Square:
					g.DrawRectangle( pen_, x-h_, y-h_, size_, size_ );
					if ( this.filled_ ) 
					{
						g.FillRectangle( brush_, x-h_, y-h_, size_, size_ );
					}
					break;

				case MarkerType.Triangle:
				case MarkerType.TriangleDown:
				{
					Point p1 = new Point( x-h_, y-h_ );
					Point p2 = new Point( x, y+h_ );
					Point p3 = new Point( x+h_, y-h_ );
					Point [] pts = new Point [3] { p1, p2, p3 };
					GraphicsPath gp = new GraphicsPath();
					gp.AddPolygon( pts );
					g.DrawPath( pen_, gp );
					if (this.filled_)
					{
						g.FillPath( brush_, gp );
					}
					break;
				}
				case MarkerType.TriangleUp:
				{
					Point p1 = new Point( x-h_, y+h_ );
					Point p2 = new Point( x, y-h_ );
					Point p3 = new Point( x+h_, y+h_ );
					Point [] pts = new Point [3] { p1, p2, p3 };
					GraphicsPath gp = new GraphicsPath();
					gp.AddPolygon( pts );
					g.DrawPath( pen_, gp );
					if (this.filled_) 
					{
						g.FillPath( brush_, gp );
					}
					break;
				}
				case MarkerType.FilledCircle:
					g.DrawEllipse( pen_, x-h_, y-h_, size_, size_ );
					g.FillEllipse( brush_, x-h_, y-h_, size_, size_ );
					break;

				case MarkerType.FilledSquare:
					g.DrawRectangle( pen_, x-h_, y-h_, size_, size_ );
					g.FillRectangle( brush_, x-h_, y-h_, size_, size_ );
					break;

				case MarkerType.FilledTriangle:
				{
					Point p1 = new Point( x-h_, y-h_ );
					Point p2 = new Point( x, y+h_ );
					Point p3 = new Point( x+h_, y-h_ );
					Point [] pts = new Point [3] { p1, p2, p3 };
					GraphicsPath gp = new GraphicsPath();
					gp.AddPolygon( pts );
					g.DrawPath( pen_, gp );
					g.FillPath( brush_, gp );
					break;
				}
				case MarkerType.Diamond:
				{
					Point p1 = new Point( x-h_, y );
					Point p2 = new Point( x, y-h_ );
					Point p3 = new Point( x+h_, y );
					Point p4 = new Point( x, y+h_ );
					Point [] pts = new Point [4] { p1, p2, p3, p4 };
					GraphicsPath gp = new GraphicsPath();
					gp.AddPolygon( pts );
					g.DrawPath( pen_, gp );
					if (this.filled_)
					{
						g.FillPath( brush_, gp );
					}
					break;
				}
				case MarkerType.Flag:
				case MarkerType.FlagUp:
				{
					Point p1 = new Point( x, y );
					Point p2 = new Point( x, y-size_ );
					Point p3 = new Point( x+size_, y-size_+size_/3 );
					Point p4 = new Point( x, y-size_+2*size_/3 );
					g.DrawLine( pen_, p1, p2 );
					Point [] pts = new Point [3] { p2, p3, p4 };
					GraphicsPath gp = new GraphicsPath();
					gp.AddPolygon( pts );
					g.DrawPath( pen_, gp );
					if (this.filled_)
					{
						g.FillPath( brush_, gp );
					}
					break;
				}
				case MarkerType.FlagDown:
				{
					Point p1 = new Point( x, y );
					Point p2 = new Point( x, y+size_ );
					Point p3 = new Point( x+size_, y+size_-size_/3 );
					Point p4 = new Point( x, y+size_-2*size_/3 );
					g.DrawLine( pen_, p1, p2 );
					Point [] pts = new Point [3] { p2, p3, p4 };
					GraphicsPath gp = new GraphicsPath();
					gp.AddPolygon( pts );
					g.DrawPath( pen_, gp );
					if (this.filled_)
					{
						g.FillPath( brush_, gp );
					}
					break;
				}
				case MarkerType.None:
					break;
			}

		}


	}
}
