using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
using System.Resources;
using System.Reflection;

namespace nft.controls
{
	/// <summary>
	/// HeightBar の概要の説明です。
	/// </summary>
	public class HeightBar : System.Windows.Forms.UserControl
	{
		private System.Windows.Forms.Button btnUp;
		private System.Windows.Forms.PictureBox barArea;
		private System.Windows.Forms.Button btnDown;
		private System.ComponentModel.IContainer components;
		private Bitmap bmGauge;
		private bool loaded = false;
		static private Bitmap bmGround;
		private System.Windows.Forms.ImageList imageList;
		private GripLabel grip;
		static private Bitmap bmInfinity;

		static HeightBar(){
			try{		
				// TODO!!!!			  
				ResourceManager rm = new ResourceManager("nft.controls.resources",Assembly.GetExecutingAssembly());
				String [] sa = Assembly.GetExecutingAssembly().GetManifestResourceNames();
				for(int i =0; i<sa.Length; i++)
					Debug.WriteLine(sa[i]);

				bmGround = rm.GetObject("Image.Ground") as Bitmap;
				bmInfinity = rm.GetObject("Image.Infinity") as Bitmap;
			}catch(Exception e){
				Debug.WriteLine(e.Message);
				Debug.WriteLine(e.StackTrace);
			}
		}

		public HeightBar()
		{
			// この呼び出しは、Windows.Forms フォーム デザイナで必要です。
			InitializeComponent();
			grip = new GripLabel();
			Controls.Add(grip);			
		}

		#region colorProperties
		private Color clGrid = SystemColors.WindowText;
		private Color clGridSelect = SystemColors.HighlightText;
		private Color clFillAbove = SystemColors.Window;
		private Color clFillGround = SystemColors.Window;
		private Color clFillUnder = SystemColors.Window;
		private Color clFillAboveSelect = SystemColors.Highlight;
		private Color clFillGroundSelect = SystemColors.Highlight;
		private Color clFillUnderSelect = SystemColors.Highlight;

		public Color GridColor { get { return clGrid; } set { clGrid = value; createGaugeImage(); } }
		public Color GridSelectedColor { get { return clGridSelect; } set { clGridSelect = value; createGaugeImage(); } }
		public Color FillAboveGroundColor { get { return clFillAbove; } set { clFillAbove = value; createGaugeImage(); } }
		public Color FillAboveGroundSelectedColor { get { return clFillAboveSelect; } set { clFillAboveSelect = value; createGaugeImage(); } }
		public Color FillOnGroundColor { get { return clFillGround; } set { clFillGround = value; createGaugeImage(); } }
		public Color FillOnGroundSelectedColor { get { return clFillGroundSelect; } set { clFillGroundSelect = value; createGaugeImage(); } }
		public Color FillUnderGroundColor { get { return clFillUnder; } set { clFillUnder = value; createGaugeImage(); } }
		public Color FillUnderGroundSelectedColor { get { return clFillUnderSelect; } set { clFillUnderSelect = value; createGaugeImage(); } }
		#endregion

		private int aboveTicks = 10;
		private int underTicks = 4;
		private int tickHeight;
		private int groundHeight = 0;
		private int infiniHeight = 0;

		public int TicksAboveGround { 
			get { return aboveTicks; } 
			set{ aboveTicks = Math.Min(100,Math.Max(0,value)); createGaugeImage(); }
		}
		public int TicksUnderGround { 
			get { return underTicks; } 
			set{ underTicks = Math.Min(100,Math.Max(0,value)); createGaugeImage(); }
		}

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


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

		protected void createGaugeImage(){
			if(!loaded && !DesignMode) return;
			if(bmGauge!=null)
				bmGauge.Dispose();
			int barHeight = barArea.Height;
			int barWidth = barArea.Width;
			bmGauge = new Bitmap(barWidth,barHeight);
			int n = TicksAboveGround+TicksUnderGround+2;
			if(n*2>barHeight){
				tickHeight = 2;
				if((TicksUnderGround+2)*2>barHeight){
					aboveTicks=0;
					int t = (barHeight>>1)-2;
					underTicks=t;
					if(t<0) 
						tickHeight = 0;
				}else{
					aboveTicks=(barHeight>>1)-TicksUnderGround-2;
				}
			} else {
				tickHeight = (int)Math.Floor((barHeight-1)/(double)n);
			}
			if(tickHeight!=0){
				int m = barHeight - n*tickHeight;
				int gh = bmGround.Height;
				if((m+tickHeight)>gh) {
					groundHeight = Math.Max(gh,tickHeight);
					infiniHeight = (tickHeight<<1) + m - groundHeight;
				}
				else {
					groundHeight = tickHeight;
					infiniHeight = tickHeight+m;
				}
			}
			
			using(Graphics g = Graphics.FromImage(bmGauge)){
				using( BrushSet bs = new BrushSet(this) ){
					if(tickHeight==0){
						g.FillRectangle(SystemBrushes.Control,0,0,barWidth,barHeight);
					}else {
						int y = TicksAboveGround*tickHeight+infiniHeight;
						g.FillRectangle(bs.AboveGround,0,0,barWidth,y);
						g.FillRectangle(bs.Ground,0,y,barWidth,groundHeight);
						y += groundHeight;
						g.FillRectangle(bs.UnderGround,0,y,barWidth,barHeight-y);

						barWidth--;
						g.DrawRectangle(bs.Grid,0,-1,barWidth,infiniHeight);
						int h = infiniHeight-1;
						for(int i=0; i<TicksAboveGround; i++){
							g.DrawRectangle(bs.Grid,0,h,barWidth,tickHeight);
							h+=tickHeight;
						}
						g.DrawRectangle(bs.Grid,0,h,barWidth,groundHeight);
						h+=groundHeight;
						for(int i=0; i<TicksUnderGround; i++){
							g.DrawRectangle(bs.Grid,0,h,barWidth,tickHeight);
							h+=tickHeight;
						}
					}
				}
			}
			barArea.Image = bmGauge;
		}

		/// <summary>
		/// 使用されているリソースに後処理を実行します。
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing ) {
				if(components != null) {
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		protected override void OnVisibleChanged(EventArgs e) {
			base.OnVisibleChanged (e);
			if(!loaded){
				loaded = true;
				createGaugeImage();			
			}
		}


		#region コンポーネント デザイナで生成されたコード 
		/// <summary>
		/// デザイナ サポートに必要なメソッドです。このメソッドの内容を
		/// コード エディタで変更しないでください。
		/// </summary>
		private void InitializeComponent()
		{
			this.components = new System.ComponentModel.Container();
			System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(HeightBar));
			this.btnUp = new System.Windows.Forms.Button();
			this.imageList = new System.Windows.Forms.ImageList(this.components);
			this.btnDown = new System.Windows.Forms.Button();
			this.barArea = new System.Windows.Forms.PictureBox();
			this.SuspendLayout();
			// 
			// btnUp
			// 
			this.btnUp.Dock = System.Windows.Forms.DockStyle.Top;
			this.btnUp.Font = new System.Drawing.Font("ＭＳ Ｐゴシック", 5.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(128)));
			this.btnUp.ImageIndex = 0;
			this.btnUp.ImageList = this.imageList;
			this.btnUp.Location = new System.Drawing.Point(0, 0);
			this.btnUp.Name = "btnUp";
			this.btnUp.Size = new System.Drawing.Size(13, 13);
			this.btnUp.TabIndex = 1;
			// 
			// imageList
			// 
			this.imageList.ColorDepth = System.Windows.Forms.ColorDepth.Depth4Bit;
			this.imageList.ImageSize = new System.Drawing.Size(7, 6);
			this.imageList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageList.ImageStream")));
			this.imageList.TransparentColor = System.Drawing.Color.White;
			// 
			// btnDown
			// 
			this.btnDown.Dock = System.Windows.Forms.DockStyle.Bottom;
			this.btnDown.Font = new System.Drawing.Font("ＭＳ Ｐゴシック", 5.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(128)));
			this.btnDown.ImageIndex = 1;
			this.btnDown.ImageList = this.imageList;
			this.btnDown.Location = new System.Drawing.Point(0, 137);
			this.btnDown.Name = "btnDown";
			this.btnDown.Size = new System.Drawing.Size(13, 13);
			this.btnDown.TabIndex = 1;
			// 
			// barArea
			// 
			this.barArea.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
				| System.Windows.Forms.AnchorStyles.Left) 
				| System.Windows.Forms.AnchorStyles.Right)));
			this.barArea.Location = new System.Drawing.Point(0, 13);
			this.barArea.Name = "barArea";
			this.barArea.Size = new System.Drawing.Size(13, 124);
			this.barArea.TabIndex = 2;
			this.barArea.TabStop = false;
			// 
			// HeightBar
			// 
			this.Controls.Add(this.btnUp);
			this.Controls.Add(this.btnDown);
			this.Controls.Add(this.barArea);
			this.Name = "HeightBar";
			this.Size = new System.Drawing.Size(13, 150);
			this.ResumeLayout(false);

		}
		#endregion
	}

	class GripLabel : Label {
		private Color border;

		public Color BorderColor { get { return border; } set { border = value; Invalidate(); } }
		protected override void OnPaint(PaintEventArgs e) {
			base.OnPaint (e);
			using(Pen p = new Pen(border)){
				e.Graphics.DrawRectangle(p,0,0,Width-1,Height-1);
			}
		}

	}

	class BrushSet : IDisposable {
		#region 
		enum BrushIndex { above, ground, under, aboveSel, groundSel, underSel };
		Brush[] brushes;
		Pen normal,selected;

		public BrushSet(HeightBar owner){
			brushes = new Brush[6];
			normal = new Pen(owner.GridColor);
			selected =new Pen(owner.GridSelectedColor);
			brushes[(int)BrushIndex.above] =new SolidBrush(owner.FillAboveGroundColor);
			brushes[(int)BrushIndex.ground] =new SolidBrush(owner.FillOnGroundColor);
			brushes[(int)BrushIndex.under] =new SolidBrush(owner.FillUnderGroundColor);
			brushes[(int)BrushIndex.aboveSel] =new SolidBrush(owner.FillAboveGroundSelectedColor);
			brushes[(int)BrushIndex.groundSel] =new SolidBrush(owner.FillOnGroundSelectedColor);
			brushes[(int)BrushIndex.underSel] =new SolidBrush(owner.FillUnderGroundSelectedColor);			
		}

		public Pen Grid { get { return normal; }}
		public Pen GridSelected { get { return selected; }}
		public Brush AboveGround { get { return brushes[(int)BrushIndex.above]; }}
		public Brush AboveSelected { get { return brushes[(int)BrushIndex.aboveSel]; }}
		public Brush Ground { get { return brushes[(int)BrushIndex.ground]; }}
		public Brush GroundSelected { get { return brushes[(int)BrushIndex.groundSel]; }}
		public Brush UnderGround { get { return brushes[(int)BrushIndex.under]; }}
		public Brush UnderSelected { get { return brushes[(int)BrushIndex.underSel]; }}

		public void Dispose() {
			normal.Dispose();
			selected.Dispose();
			normal = null;
			selected = null;
			for(int i=0; i<brushes.Length; i++ ) {
				brushes[i].Dispose();
			}
			brushes = null;
		}
		#endregion
	}
}
