using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Drawing;

namespace pcd_g1
{
	static class ReadStgFile
	{

		public static IEnumerable<IStageObject> ReadStageFile(string fname, out int width, out int height, Stage stg)
		{
			string line = "";
			string[] tokens;
			var stgobjList = new List<IStageObject>();
			var translationList = new Dictionary<char, int>();
			width = 0; height = 0;

			try
			{
				using (var reader = new StreamReader(fname))
				{
					//ヘッダ::ステージサイズ
					tokens = (line = reader.ReadLine()).Split(',');
					width = (int)Math.Ceiling((decimal)(int.Parse(tokens[0]) / 32));
					height = (int)Math.Ceiling((decimal)(int.Parse(tokens[1]) / 32));

					//空白行
					while ((line = reader.ReadLine()) != null && line == "") ;

					do
					{
						tokens = line.Split('=');
						if (tokens[0].Length != 1)
						{
							throw new ApplicationException("Warning: 文字定義の左辺'" + tokens[0] + "'は一文字である必要があります");
						}
						if (tokens[1].Contains(' ')) tokens[1] = tokens[1].Remove(tokens[1].IndexOf(' '));
						translationList.Add(tokens[0][0], int.Parse(tokens[1]));
					} while ((line = reader.ReadLine()) != null && line != "");
					

					//空白行
					while ((line = reader.ReadLine()) != null && line == "") ;

					//マップ
					for (int y = 0; y < height; y++)
					{
						if (line != null)
						{
							for (int x = 0; x < line.Length; x++)
							{
								char ch = line[x];
								int ind = -1;
								if (x >= width)
								{
									break;
								}
								if (ch != ' ')
								{
									if (translationList.ContainsKey(ch))
									{
										ind = translationList[ch];
									}
									else
									{
										throw new ApplicationException("Warning: 定義されていない文字'" + ch + "'");
									}
									stgobjList.Add(GetStageObjectFromID(ind, x * 32, y * 32, stg));
								}
							}
						}
						line = reader.ReadLine();
					}

					//空白行
					while ((line = reader.ReadLine()) != null && line == "") ;

					if (line != null)
					{
						do
						{
							var units = line.Split(':');
							if (units.Length > 1)
							{
								var id = int.Parse(units[0]);
								var arg = units[1];
								tokens = arg.Split(',');
								int x = int.Parse(tokens[1]) * 32;
								int y = int.Parse(tokens[2]) * 32;
								if (tokens.Length > 4)
								{
									x += int.Parse(tokens[3]);
									y += int.Parse(tokens[4]);
								}
								string param = "";
								if (tokens.Length > 5) param = tokens[5];
								stgobjList.Add(GetStageObjectFromID(id, x, y, stg, param));
							}
						}
						while ((line = reader.ReadLine()) != null && line != "");
					}
				}
			}
			catch (FileNotFoundException ex)
			{

				Debug.WriteLine(string.Format("Stageファイルが見つかりません!!\nファイル: {0}", ex.FileName));

				return null;
			}
			catch (IndexOutOfRangeException)
			{
				Debug.WriteLine(string.Format("Format error."));
				return null;
			}
			catch (InvalidCastException)
			{
				Debug.WriteLine(string.Format("Format error."));
				return null;
			}
			return stgobjList.ToArray();
		}
		
		public static IStageObject GetStageObjectFromID(int id, int x, int y, Stage stg, string param = "")
		{
			switch(id)
			{
				case 130:case 131:case 132:case 133:case 134:case 135: case 137: case 138:
				case 136:case 140:case 214:case 216:case 222:case 232:
				case 233:case 150: case 158: case 160: case 168: case 170: case 190: case 198:
				case 178:
					return new FreeBlockStageObject(x, y, id.ToString());
				case 243: case 245:
					return new KaminariBlockStageObject(x, y, stg);
				case 411: case 410:
					return new AkudamaCharacterStageObject(x, y, stg);
				case 420: case 421:
					return new AkudamaCharacterStageObject(x, y, stg, 42);
				case 431: case 430:
					return new AkudamaCharacterStageObject(x, y, stg, 43);
				case 441: case 440:
					return new AkudamaCharacterStageObject(x, y, stg, 44);
				case 450: case 451:
					return new AkudamaRedCharacterStageObject(x, y, stg);
				case 460: case 461:
					return new AkudamaRedCharacterStageObject(x, y, stg,46);
				case 470: case 471:
					return new AkudamaRedCharacterStageObject(x, y, stg,47);
				case 480: case 481:
					return new AkudamaRedCharacterStageObject(x, y, stg,48);
				case 970: case 971:
					return new ZoukinCharacterStageObject(x, y, stg);
				case 960: case 961:
					return new BanakeCharacterStageObject(x, y, stg);
				case 865: case 866: case 867: case 868:
					return new TogeBlockStageObject(x, y, id.ToString());
				case 153: case 163: case 173: case 212: case 213: case 215: case 193: case 183:		//真ん中まで
					return new SlopeTypeBBlockStageObject(x, y, id.ToString());
				case 151: case 161: case 171: case 191:			//右下がり45度
					return new SlopeTypeCBlockStageObject(x, y, id.ToString(), true);
				case 152: case 162: case 172: case 192:			//左下がり45度
					return new SlopeTypeCBlockStageObject(x, y, id.ToString(), false);
				case 154: case 164: case 174: case 194:			//右下がり真ん中まで
					return new SlopeTypeDBlockStageObject(x, y, id.ToString(), true);
				case 155: case 165: case 175: case 195:			//左下がり真ん中まで
					return new SlopeTypeDBlockStageObject(x, y, id.ToString(), false);
				case 156: case 166: case 176: case 196:			//右下がり真ん中から
					return new SlopeTypeEBlockStageObject(x, y, id.ToString(), true);
				case 157: case 167: case 177: case 197:			//左下がり真ん中から
					return new SlopeTypeEBlockStageObject(x, y, id.ToString(), false);
				case 923:								//入口( StartMenuStageに)
					if (param != "")
					{
						string[] args = param.Split(',');
						if (args.Length == 3)
						{
							return new DoorItemStageObject(x, y, stg, args[0], int.Parse(args[1]),int.Parse(args[2]));
						}
						return new DoorItemStageObject(x, y, stg, param);
					}
					else
					{
						return new DoorItemStageObject(x, y, stg, typeof(startMenuStage));
					}
				case 924:								//ワープ( 64, 64に)
					if (param != "")
					{
						if (param.Contains(','))
						{
							int xd, yd;
							string xs = param.Substring(0, param.IndexOf(','));
							string ys = param.Substring(param.IndexOf(',') + 1);
							if (int.TryParse(xs, out xd) && int.TryParse(ys, out yd))
							{
								return new WarpItemStageObject(x, y, stg, xd, yd);
							}
						}
						Debug.WriteLine("ワープ: パラメータが不正確です。param:" + param);
					}
					return new WarpItemStageObject(x, y, stg, 64, 64);
				case 925:								//セーブ
					return new SaveItemStageObject(x, y, stg, param == "true");
				case 926:								//スイッチ(何もしない)
					if (param != "")
					{
						if (param.Contains(','))
						{
							string key = param.Substring(0, param.IndexOf(','));
							int val;
							if (key != "" && int.TryParse(param.Substring(param.IndexOf(',') + 1), out val))
							{
								return new SwitchItemStageObject(x, y, stg, key, val);
							}
						}
						Debug.WriteLine("スイッチ: パラメータが不正確です。param:" + param);
					}
					return new SwitchItemStageObject(x, y, stg);
				case 702:								//スキル
					if (param != "")
					{
						int val;
						if (int.TryParse(param, out val))
						{
							return new HealItemStageObject(x, y, stg, val);
						}
						Debug.WriteLine("ハート: パラメータが不正確です。param:" + param);
					}
					return new HealItemStageObject(x, y, stg);
				case 931: case 932: case 933:
					return new TogeBlockStageObject(x, y, id.ToString(), 10);
				case 913: case 912: case 915: case 934:
				case 661: case 662: case 691: case 692: case 671: case 672:
				case 681: case 682:
					return new FreePictureItemStageObject(x, y, stg, ImageManager.Search(id.ToString()));
				case 911:
					return new BulletinBoardItemObject(x, y, stg, param==""? "この先工事中.. (このメッセージを編集してください)":param.Replace("\\n","\n"));
				case 701: //skill
					return new SkillItemStageObject(x, y, stg);
				case 242:	//cloud
					return new CloudBlockStageObject(x, y);
				case 821: case 822:	//泡
					return new JumpBlockStageObject(x, y, "821", 10, 3f, 3f, 26f, 26f);
				case 861:
					//return new JumpBlockStageObject(x, y, "861", 10, 3f, 3f, 26f, 26f);
					return new RakusekiBlockStageObject(x, y, stg);
				case 999:  //コマンド
					if (param != "")
					{
						if (param.Contains(','))
						{
							return new CommandableItemStageObject(x, y, stg, param.Substring(param.LastIndexOf(',') + 1));
						}
					}
					return new CommandableItemStageObject(x, y, stg);
                case 935:
                    return new BananaBlockStageObject(x, y, stg);
				case 950:
					return new HedoronCharacterStageObject(x, y, stg);
				case 520: case 521:
					return new BadBearCharacterStageObject(x, y, stg);
				case 530:
					return new KaityouCharacterStageObject(x, y, stg);
				case 540:
					return new TaisanbokunoSeiCharacterStageObject(x, y, stg);
				case 940: case 947: case 944:
					return new DorotumuriCharacterStageObject(x, y, stg, 3, 0);
				case 941: case 946: case 945:
					return new DorotumuriCharacterStageObject(x, y, stg, 0, 3);
				default:
					//return new FreeBlockStageObject(x, y, id.ToString());
					Bitmap img = new Bitmap(Properties.Resources.undefined);
					Graphics gr = Graphics.FromImage(img);
					gr.DrawString(id.ToString(), new Font("MS Gothic", 12), Brushes.Black, 0, 0);
					gr.Dispose();
					return new NormalBlockStageObject(x, y, img);

			}//id追加時に対応するクラスをここに列挙する
		}

		
	}
}
