///////////////////
// CardboardBox.cs
///////////////////
using System;
using System.Collections;
using System.Collections.Generic;	//List使用の為
using System.Windows.Forms;
using System.Drawing;
using System.Resources;
using System.IO;					//Fileクラス使用の為
using csFileList;					//FileListクラス使用の為

namespace CardboardBox
{
	///////////////////////////
	//エントリーポイントクラス
	///////////////////////////
	class MainApp
	{
		[STAThread]
		public static void Main()
		{
			string[] cmds = System.Environment.GetCommandLineArgs();	//先頭は実行ファイル名
			if(cmds.Length > 1)
			{
				string[] args = new string[cmds.Length - 1];
				Array.Copy(cmds, 1, args, 0, cmds.Length - 1);
				Application.Run(new CbBox(args));
			}
			else
				Application.Run(new CbBox());
		}
	}

	///////////////////////
	//メインフォームクラス
	///////////////////////
	public partial class CbBox : Form
	{
		//ウィンドウのマウス移動フラグ
		private bool cbMovable = false;
		//thisの移動開始座標
		private Point cbPoint;
		//ウィンドウ画像（段ボール箱－1 = Empty、2 = Full）
		private Bitmap cbbmp1, cbbmp2;
		//ファイル名リスト用
		List<string> file_list = new List<string>();
		//コンテキストメニュー関係
		ContextMenu contextMenu;
		MenuItem mi1, mi2, mi3;
		//タスクトレイアイコン
		NotifyIcon notifyIcon;
		ContextMenuStrip NIMenuStrip;	//タスクトレイアイコンのポップアップメニュー

		//コンストラクタ
		public CbBox(string[] args = null)
		{
			//このプログラムのアッセンブリーを取得する
			System.Reflection.Assembly asm = System.Reflection.Assembly.GetExecutingAssembly();
			//プログラムアイコンをフォームにつける
			this.Icon = Icon.ExtractAssociatedIcon(asm.Location);
			//ResourceManagerインスタンスの作成
			ResourceManager rm = new ResourceManager("CardboardBox", asm);
			//data name="CBBox1"、"CBBox2"というBitmapを読み込む
			cbbmp1 = (Bitmap)rm.GetObject("CBBox1");
			cbbmp2 = (Bitmap)rm.GetObject("CBBox2");
			cbbmp1.MakeTransparent(Color.Black);
			cbbmp2.MakeTransparent(Color.Black);
			//ウィンドウ位置の設定
			this.StartPosition = FormStartPosition.CenterScreen;
			//ウィンドウ枠の設定
			this.FormBorderStyle = FormBorderStyle.None;
			/*	Fixed3D			2	固定された 3D 境界線。
			FixedDialog			3	太い固定されたダイアログ スタイルの境界線。
			FixedSingle			1	固定された一重線の境界線。
			FixedToolWindow		5	サイズ変更できないツール ウィンドウの境界線。 ツール ウィンドウは、タスクバー、またはユーザーが Alt + Tab キーを押したときに表示されるウィンドウには表示されません。 FixedToolWindow を指定するフォームはタスクバーに表示されませんが、ShowInTaskbar プロパティが false に設定されていることを確認する必要があります。既定値は true です。
			None				0	境界線なし。
			Sizable				4	サイズ変更できる境界線。
			SizableToolWindow	6	サイズ変更できるツール ウィンドウの境界線。 ツール ウィンドウは、タスクバー、またはユーザーが Alt + Tab キーを押したときに表示されるウィンドウには表示されません。
			*/
			//サイズの設定
			this.Size = new Size(128, 128);
			//常に最前面に設定
			this.TopMost = true;
			// タスクバーに表示しない
			this.ShowInTaskbar = false;
			//フォームのロードイベントメソッドを設定
			this.Load += CbBox_Load;
			//フォームのキーダウンイベントメソッドを設定
			this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.CbBox_KeyDown);
			//フォームのマウスイベントメソッドを設定
			this.MouseDown += new MouseEventHandler(this.CbBox_MouseDown);
			this.MouseUp += new MouseEventHandler(this.CbBox_MouseUp);
			this.MouseMove += new MouseEventHandler(this.CbBox_MouseMove);
			//コンテキストメニュー関連
			mi1 = new MenuItem();
			mi1.Index = 0;
			mi1.Text = "ファイルリストの表示";
			mi2 = new MenuItem();
			mi2.Index = 0;
			mi2.Text = "タスクトレイへ収納";
 			mi3 = new MenuItem();
			mi3.Index = 0;
			mi3.Text = "終了";
 			contextMenu = new ContextMenu();
			contextMenu.MenuItems.Add(mi1);
			contextMenu.MenuItems.Add("-");		//セパレーター
			contextMenu.MenuItems.Add(mi2);
			contextMenu.MenuItems.Add("-");		//セパレーター
			contextMenu.MenuItems.Add(mi3);
 			this.ContextMenu = contextMenu;
			mi1.Click += new EventHandler(FileList);
			mi2.Click += new EventHandler(TaskTray_In);
			mi3.Click += new EventHandler(Exit);
			//NotifyIconの設定
			notifyIcon = new NotifyIcon();
			notifyIcon.Icon = this.Icon;
			notifyIcon.Visible = true;
			notifyIcon.Text = "CardboardBox - クリックして表示";	//アイコンのテキスト
			notifyIcon.Click += TaskTray_Out;						//NotifyIconのクリックイベント
			//NotifyIconのコンテキストメニューの設定
			NIMenuStrip = new ContextMenuStrip();
			ToolStripMenuItem tsMenuItem = new ToolStripMenuItem();
			tsMenuItem.Text = "&終了";
			tsMenuItem.Click += Exit;
			NIMenuStrip.Items.Add(tsMenuItem);
			notifyIcon.ContextMenuStrip = NIMenuStrip;
			//Drag and Dropを受け付ける
			this.AllowDrop = true;
			//コマンドライン引数がある場合
			if(args != null)
			{
				foreach(string fn in args)
				{
					//ファイルが存在するか、フォールダーではないか、をチェックする
					if(!File.Exists(fn))
					{
						MessageBox.Show("このファイルは存在しません。\r\n" + fn, "", MessageBoxButtons.OK, MessageBoxIcon.Error);
						continue;
					}
					//Listに引数を追加する
					file_list.Add(fn);
				}
			}
		}

		//フォームのロードイベントメソッド
		private void CbBox_Load(object sender, EventArgs e)
		{
			//背景画像の設定
			this.BackgroundImageLayout = ImageLayout.Zoom;	//Center, None, Stretch, Tile, Zoom
			if(file_list.Count > 0)
				this.BackgroundImage = cbbmp2;
			else
				this.BackgroundImage = cbbmp1;
			//背景色を透過色に設定
			this.TransparencyKey = this.BackColor;
		}


		//ファイルをドラッグされた時
		protected override void OnDragEnter(DragEventArgs e)
		{
			base.OnDragEnter(e);
			if(e.Data.GetDataPresent(DataFormats.FileDrop))
				e.Effect = DragDropEffects.Copy;
			else
				e.Effect = DragDropEffects.None;
		}

		//ファイルをドロップされたとき
		protected override void OnDragDrop(DragEventArgs e)
		{
			base.OnDragDrop(e);
			//ドロップされたファイルパスを取得
			string[] files =  (string[])e.Data.GetData(DataFormats.FileDrop, false);
			//ドロップされたデータを追加する
			foreach(string fn in files)
			{
				//ファイルが存在するか、フォールダーではないか、をチェックする
				if(!File.Exists(fn))
				{
					MessageBox.Show("このファイルは存在しません。\r\n" + fn, "", MessageBoxButtons.OK, MessageBoxIcon.Error);
					continue;
				}
				//Listに引数を追加する
				file_list.Add(fn);
			}
			this.BackgroundImage = cbbmp2;
		}

		//キーダウンイベントメソッド
		private void CbBox_KeyDown(object sender,KeyEventArgs e)
		{
			//フォームを移動させるピクセル数
			int movePixel = 2;
			if(e.Shift)
				movePixel *= 8;
			switch(e.KeyCode)
			{
				//上移動
				case Keys.Up:
					this.Top -= movePixel;
					break;
				//下移動
				case Keys.Down:
					this.Top += movePixel;
					break;
				//左移動
				case Keys.Left:
					this.Left -= movePixel;
					break;
				//右移動
				case Keys.Right:
					this.Left += movePixel;
					break;
				//シフトキー（終了させない）
				case Keys.ShiftKey:
					break;
				//その他のキー
				default:
					Close();
					break;
			}
		}

		//マウスダウンイベントメソッド
		private void CbBox_MouseDown(object sender, MouseEventArgs e)
		{
			if(!cbMovable && e.Button == MouseButtons.Left)
			{
				//フラグを真にする
				cbMovable = true;
				//現在のマウス座標取得
				cbPoint = new Point(e.X, e.Y);
			}
		}

		//マウスアップイベントメソッド
		private void CbBox_MouseUp(object sender, MouseEventArgs e)
		{
			if(cbMovable && e.Button == MouseButtons.Left)
				//フラグを戻す
				cbMovable = false;
		}

		//マウスムーヴイベントメソッド
		private void CbBox_MouseMove(object sender, MouseEventArgs e)
		{
			//マウス押下中はドラッグ可
			if (cbMovable)
			{
				//フォームを移動させる
				this.Left += e.X - cbPoint.X;
				this.Top += e.Y - cbPoint.Y;
			}
		}

		public void FileList(object sender, EventArgs e)
		{
			/* 注釈 from Microsoft Docs
			このメソッドを使用すると、アプリケーションにモーダルダイアログボックスを表示できます。
			このメソッドが呼び出されると、ダイアログ ボックスが閉じられるまで次のコードは実行されません。
			ダイアログボックスは、フォームのDialogResultプロパティに、DialogResultの一つを割り当てるか、
			コードでDialogResultの列挙値の1つをButtonに設定することができます。
			この値は、このメソッドによって返されます。この戻り値を使用して、ダイアログボックスで発生した
			アクションを処理する方法を決定できます。たとえば、ダイアログボックスが閉じられ、このメソッドを
			使用して値DialogResult.Cancelが返された場合、呼び出しShowDialogに続くコードが実行されないように
			することができます。
			フォームがモーダルダイアログボックスとして表示されている場合、[閉じる]ボタン(フォームの右上隅にある
			Xボタン) をクリックすると、フォームが非表示になり、DialogResultプロパティがDialogResult.Cancelに設定
			されます。非モーダルフォームとは異なり、ユーザーがダイアログボックスの閉じる（Close）フォームボタン
			をクリックしたり、プロパティの値DialogResultを設定したりしても、メソッドは.NET Frameworkによって
			呼び出されません。代わりに、フォームは非表示になり、ダイアログ ボックスの新しいインスタンスを作成
			せずに再度表示できます。ダイアログ ボックスとして表示されるフォームは閉じるのではなく非表示になる
			ため、フォームがアプリケーションで不要になった場合は、フォームのメソッドを呼び出す Dispose 必要が
			あります。
			このバージョンのShowDialogメソッドでは、フォームまたはコントロールを所有者として指定しません。
			このバージョンが呼び出されると、現在アクティブなウィンドウがダイアログ ボックスの所有者になります。
			特定の所有者を指定する場合は、このメソッドの他のバージョンを使用します。
			*/
			//ファイルリストを文字列配列に変換
			string[] strArray = file_list.ToArray();
			//FileListクラスダイアログを作成、表示（上記参照）
			FileList fl = new FileList(strArray);
			fl.ShowDialog();
			//flに残っているリストを承継してから
			file_list.Clear();
			file_list.AddRange(fl.GetFileList());
			if(file_list.Count > 0)
			{
				//初期化確認
				DialogResult dr = MessageBox.Show("FileLIst処理が終了したのでファイルデータを初期化します。\r\n宜しいですか？", "確認", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
				if(dr == DialogResult.Yes)
				{
					file_list.Clear();
					this.BackgroundImage = cbbmp1;
				}
				else
					this.BackgroundImage = cbbmp2;
			}
			else
				this.BackgroundImage = cbbmp1;
			//FileListクラスダイアログインスタンスの開放
			fl.Dispose();
		}

		//「タスクトレイへ収納」
		public void TaskTray_In(object sender, EventArgs e)
		{
			this.Visible = false;
		}

		//（タスクトレイから）「表示」
		public void TaskTray_Out(object sender, EventArgs e)
		{
			this.Visible = true;
		}
/*
		public void FileOpen(object sender, EventArgs e)
		{
			DialogResult dr = MessageBox.Show("ファイルリスト入れ替えますか（はい）、または\r\n追加しますか（いいえ）？", "確認", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
			if(dr == DialogResult.Yes)
			{
				file_list.Clear();				//入替えの場合、リストビュー内の項目を全削除
			}
			OpenFileDialog ofDlg = new OpenFileDialog();
			ofDlg.Filter = "アルバムファイル(*.alb)|*.alb|プレイリストファイル(*.plf)|*.plf|すべてのファイル(*.*)|*.*";	//ファイルフィルターの指定
			ofDlg.FilterIndex = 1;						//ファイルフィルターインデックスの指定
			ofDlg.RestoreDirectory = true;				//ダイアログボックスを閉じる前に現在のディレクトリを復元するようにする
			ofDlg.CheckFileExists = true;				//存在しないファイルの名前が指定されたとき警告を表示する
			ofDlg.CheckPathExists = true;				//存在しないパスが指定されたとき警告を表示する
			ofDlg.InitialDirectory = @".\";				//デフォルトのフォルダを指定する
			ofDlg.Title = "ファイルリストを開く";		//ダイアログのタイトルを指定する
			if(ofDlg.ShowDialog() == DialogResult.OK)	//ダイアログを表示する
			{
				//ファイル("shift_jis")を開く
				using(StreamReader sr = new StreamReader(ofDlg.FileName, System.Text.Encoding.GetEncoding("shift_jis")))
				{
					//1行ずつ処理
					while(!sr.EndOfStream){
						string line = sr.ReadLine();
						//カンマで配列要素を分ける（最初の要素がファイルパス、名を前提とする）
		    			string[] fns = line.Split(',');
		    			//第1要素のファイルパス、名が'"'で括られていれば削除する
		    			string fn = fns[0].Trim('"');
						//ファイルが存在するか、フォールダーではないか、をチェックする
						if(!File.Exists(fn))
						{
							MessageBox.Show("このファイルは存在しません。\r\n" + fn, "", MessageBoxButtons.OK, MessageBoxIcon.Error);
							continue;
						}
						//Listに引数を追加する
						file_list.Add(fn);
					}
					sr.Close();
				}
 			}
			else
			{
				MessageBox.Show("キャンセルされました。", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
			//オブジェクトを破棄する
			ofDlg.Dispose();
			if(file_list.Count > 0)
				this.BackgroundImage = cbbmp2;
		}
*/

		public void Exit(object sender, EventArgs e)
		{
			//終了処理
			DialogResult dr = MessageBox.Show("終了しますか？", "確認", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
			if(dr == DialogResult.Yes)
			{
				cbbmp1.Dispose();
				cbbmp2.Dispose();
				Close();
			}
		}
	}
}
