using System;

namespace Exp00080
{
	// 
	abstract class BinaryReadAndWrite
	{
		// 
		private System.IO.BinaryReader m_BinaryReader;
		// 
		private System.IO.BinaryWriter m_BinaryWriter;
		// 
		public BinaryReadAndWrite(
			System.IO.Stream FileReading,
			System.IO.Stream FileWriting)
		{
			m_BinaryReader = new System.IO.BinaryReader(FileReading);
			m_BinaryWriter = new System.IO.BinaryWriter(FileWriting);
		}
		// 
		public System.Byte SerializeByte()
		{
			System.Byte x = ReadByte();
			m_BinaryWriter.Write(x);
			return x;
		}
		// 
		public System.UInt16 SerializeWord()
		{
			System.UInt16 x = ReadWord();
			System.Byte[] w = new System.Byte[] {
				(System.Byte)((x >> 0) & 0xFF),
				(System.Byte)((x >> 8) & 0xFF)};
			m_BinaryWriter.Write(w);
			return x;
		}
		// 
		public System.Byte[] SerializeBytes(int n)
		{
			System.Byte[] w = ReadBytes(n);
			m_BinaryWriter.Write(w);
			return w;
		}
		// 
		public System.UInt16[] SerializeWords(int n)
		{
			System.UInt16[] w = new System.UInt16[n];
			for (int i = 0; i < n; i++) 
			{
				w[i] = SerializeWord();
			}
			return w;
		}
		// 
		protected System.Byte ReadByte()
		{
			return m_BinaryReader.ReadByte();
		}
		// 
		protected abstract System.UInt16 ReadWord();
		// 
		protected System.Byte[] ReadBytes(int n)
		{
			return m_BinaryReader.ReadBytes(n);
		}
		// 
		protected System.UInt16[] ReadWords(int n)
		{
			System.UInt16[] w = new System.UInt16[n];
			for (int i = 0; i < n; i++)
			{
				w[i] = ReadWord();
			}
			return w;
		}
	}
	// 
	class ReadWriteLE : BinaryReadAndWrite
	{
		// 
		public ReadWriteLE(
			System.IO.Stream FileReading,
			System.IO.Stream FileWriting)
			: base(FileReading, FileWriting)
		{

		}
		// 
		protected override System.UInt16 ReadWord()
		{
			return (System.UInt16)(ReadByte() + ReadByte() * 256);
		}
	}
	// 
	class ReadWriteBE : BinaryReadAndWrite
	{
		// 
		public ReadWriteBE(
			System.IO.Stream FileReading,
			System.IO.Stream FileWriting)
			: base(FileReading, FileWriting)
		{

		}
		// 
		protected override System.UInt16 ReadWord()
		{
			return (System.UInt16)(ReadByte() * 256 + ReadByte());
		}
	}
	// 
	class DungeonConverter
	{
		// 
		BinaryReadAndWrite m_BinaryRW;
		// 
		public System.UInt16 RandomGraphicsSeed;
		public System.UInt16 MapDataSize;
		public System.Byte NumberOfLevels;
		public System.UInt16 TextDataSize;
		public System.UInt16 StartingPartyPosition;
		public System.UInt16 ObjectListSize;
		public System.UInt16 NumberOfDoors;
		public System.UInt16 NumberOfTeleporters;
		public System.UInt16 NumberOfTexts;
		public System.UInt16 NumberOfActuators;
		public System.UInt16 NumberOfCreatures;
		public System.UInt16 NumberOfWeapons;
		public System.UInt16 NumberOfClothes;
		public System.UInt16 NumberOfScrolls;
		public System.UInt16 NumberOfPotions;
		public System.UInt16 NumberOfChests;
		public System.UInt16 NumberOfMiscItems;
		// 
		public System.UInt16 NumberOfColumns;
		// 
		public DungeonConverter(
			BinaryReadAndWrite BinaryRW)
		{
			m_BinaryRW = BinaryRW;
		}
		// 
		public System.Boolean ReadHeader()
		{
			try 
			{
				RandomGraphicsSeed = m_BinaryRW.SerializeWord();
				MapDataSize = m_BinaryRW.SerializeWord();
				NumberOfLevels = m_BinaryRW.SerializeByte();
				m_BinaryRW.SerializeByte();
				TextDataSize = m_BinaryRW.SerializeWord();
				StartingPartyPosition = m_BinaryRW.SerializeWord();
				ObjectListSize = m_BinaryRW.SerializeWord();
				NumberOfDoors = m_BinaryRW.SerializeWord();
				NumberOfTeleporters = m_BinaryRW.SerializeWord();
				NumberOfTexts = m_BinaryRW.SerializeWord();
				NumberOfActuators = m_BinaryRW.SerializeWord();
				NumberOfCreatures = m_BinaryRW.SerializeWord();
				NumberOfWeapons = m_BinaryRW.SerializeWord();
				NumberOfClothes = m_BinaryRW.SerializeWord();
				NumberOfScrolls = m_BinaryRW.SerializeWord();
				NumberOfPotions = m_BinaryRW.SerializeWord();
				NumberOfChests = m_BinaryRW.SerializeWord();
				NumberOfMiscItems = m_BinaryRW.SerializeWord();
				m_BinaryRW.SerializeWords(5);
				return true;
			} 
			catch (System.Exception e)
			{
				System.Console.WriteLine(e.ToString() + "\n--- Hit Enter to continue ---");
				System.Console.ReadLine();
			}
			return false;
		}
		// 
		public System.Boolean ReadLevelDefinitions()
		{
			try 
			{
				System.UInt16 i;
				NumberOfColumns = 0;
				for (i = 0; i < NumberOfLevels; i++) 
				{
					m_BinaryRW.SerializeWords(2);
					m_BinaryRW.SerializeBytes(4);
					NumberOfColumns += (System.UInt16)(((m_BinaryRW.SerializeWord() >> 6) & 0x1F) + 1);
					m_BinaryRW.SerializeWords(3);
				}
				return true;
			}
			catch (System.Exception e)
			{
				System.Console.WriteLine(e.ToString() + "\n--- Hit Enter to continue ---");
				System.Console.ReadLine();
			}
			return false;
		}
		// 
		public long ComputeSize()
		{
			long n = 44
				+ NumberOfLevels * 16
				+ NumberOfColumns * 2
				+ ObjectListSize * 2
				+ TextDataSize * 2
				+ NumberOfDoors * 4
				+ NumberOfTeleporters * 6
				+ NumberOfTexts * 4
				+ NumberOfActuators * 8
				+ NumberOfCreatures * 16
				+ NumberOfWeapons * 4
				+ NumberOfClothes * 4
				+ NumberOfScrolls * 4
				+ NumberOfPotions * 4
				+ NumberOfChests * 8
				+ NumberOfMiscItems * 4
				+ MapDataSize;
			return n;
		}
		// 
		public System.Boolean ConvertDungeon()
		{
			System.UInt16 i;

			try
			{
				for (i = 0; i < NumberOfColumns; i++)
				{
					m_BinaryRW.SerializeWord();
				}
				for (i = 0; i < ObjectListSize; i++)
				{
					m_BinaryRW.SerializeWord();
				}
				for (i = 0; i < TextDataSize; i++)
				{
					m_BinaryRW.SerializeWord();
				}
				for (i = 0; i < NumberOfDoors; i++)
				{
					m_BinaryRW.SerializeWords(2);
				}
				for (i = 0; i < NumberOfTeleporters; i++)
				{
					m_BinaryRW.SerializeWords(3);
				}
				for (i = 0; i < NumberOfTexts; i++)
				{
					m_BinaryRW.SerializeWords(2);
				}
				for (i = 0; i < NumberOfActuators; i++)
				{
					m_BinaryRW.SerializeWords(4);
				}
				for (i = 0; i < NumberOfCreatures; i++)
				{
					m_BinaryRW.SerializeWords(2);
					m_BinaryRW.SerializeBytes(2);
					m_BinaryRW.SerializeWords(5);
				}
				for (i = 0; i < NumberOfWeapons; i++)
				{
					m_BinaryRW.SerializeWords(2);
				}
				for (i = 0; i < NumberOfClothes; i++)
				{
					m_BinaryRW.SerializeWords(2);
				}
				for (i = 0; i < NumberOfScrolls; i++)
				{
					m_BinaryRW.SerializeWords(2);
				}
				for (i = 0; i < NumberOfPotions; i++)
				{
					m_BinaryRW.SerializeWords(2);
				}
				for (i = 0; i < NumberOfChests; i++)
				{
					m_BinaryRW.SerializeWords(4);
				}
				for (i = 0; i < NumberOfMiscItems; i++)
				{
					m_BinaryRW.SerializeWords(2);
				}
				m_BinaryRW.SerializeBytes(MapDataSize);

				m_BinaryRW.SerializeWord();

				return true;
			} 
			catch (System.Exception e)
			{
				System.Console.WriteLine(e.ToString() + "\n--- Hit Enter to continue ---");
				System.Console.ReadLine();
			}
			return false;
		}
	};
	// 
	class Class1
	{
		// 
		enum ENDIAN_TYPE
		{
			LITTLE_ENDIAN,
			BIG_ENDIAN,
		};
		// 
		[STAThread]
		static void Main(string[] args)
		{
			System.String Arg0 = System.Environment.GetCommandLineArgs()[0];

			if (args.Length == 0)
			{
				PayAttention(""
					+ "Converts dungeon files between little endian (PC) and big endian (Atari ST, Amiga, X68000, Macintosh, SegaCD) formats.\n"
					+ "Usage example: at a command prompt, type the following command line:\n"
					+ "   DungeonConverter.vbs DUNGEON.DAT\n"
					+ "You can also drag and drop a dungeon file on DungeonConverter.vbs in Windows Explorer.\n"
					+ "The converted file will be saved in the script's folder.\n"
					+ "Background information:\n"
					+ "In dungeon files, some data is stored as single bytes, and some is stored as words (pairs of bytes). Words can be stored as little endian (least significant byte first) or big endian (most significant byte first).\n"
					+ "Little endian is used in PC versions of Dungeon Master, Chaos Strikes Back and Dungeon Master II.\n"
					+ "Big endian is used in Atari ST, Amiga, X68000, Macintosh and SegaCD versions of Dungeon Master, Chaos Strikes Back and Dungeon Master II.\n"
					+ "This script will automatically detect the format of the input file and convert it to the other format by swapping the bytes in each word of data.\n");
			}
			else
			{
				System.String SourceFileName = args[0];

				if (!System.IO.File.Exists(SourceFileName)) 
				{
					PayAttention(""
						+ "File not found: " + SourceFileName + "\n");
				}
				else
				{
					try
					{
						System.IO.Stream SourceFile = System.IO.File.OpenRead(SourceFileName);
						long SourceFileSize = SourceFile.Length;
						if (SourceFileSize < 44)
						{
							PayAttention(""
								+ "Incorrect dungeon file (File is too small for header).\n");
						}
						else
						{
							System.Boolean EndianOK;
							System.IO.MemoryStream Incoming;
							DungeonConverter Which = null;

							SourceFile.Seek(0, System.IO.SeekOrigin.Begin);
							ReadWriteLE SerialLE = new ReadWriteLE(SourceFile, Incoming = new System.IO.MemoryStream());
							DungeonConverter TryLE = new DungeonConverter(SerialLE);

							EndianOK = true;
							ENDIAN_TYPE Endian = ENDIAN_TYPE.LITTLE_ENDIAN;

							if (!TryLE.ReadHeader() || SourceFileSize < 44 + (TryLE.NumberOfLevels * 16))
							{
								EndianOK = false;
							}
							else
							{
								if (!TryLE.ReadLevelDefinitions() || ((SourceFileSize != TryLE.ComputeSize()) && (SourceFileSize != TryLE.ComputeSize() + 2)))
								{
									EndianOK = false;
								}
								else
								{
									Which = TryLE;
								}
							}

							if (!EndianOK)
							{
								SourceFile.Seek(0, System.IO.SeekOrigin.Begin);
								ReadWriteBE SerialBE = new ReadWriteBE(SourceFile, Incoming = new System.IO.MemoryStream());
								DungeonConverter TryBE = new DungeonConverter(SerialBE);

								EndianOK = true;
								Endian = ENDIAN_TYPE.BIG_ENDIAN;

								if (!TryBE.ReadHeader() || (SourceFileSize < 44 + (TryBE.NumberOfLevels * 16)))
								{
									EndianOK = false;
								}
								else
								{
									if (!TryBE.ReadLevelDefinitions() || ((SourceFileSize != TryBE.ComputeSize()) && (SourceFileSize != TryBE.ComputeSize() + 2)))
									{
										EndianOK = false;
									}
									else
									{
										Which = TryBE;
									}
								}
							}

							if (!EndianOK)
							{
								PayAttention(
									"Invalid dungeon file.\n");
							}
							else
							{
								if (Endian == ENDIAN_TYPE.LITTLE_ENDIAN)
								{
									PayAttention(
										"The input dungeon file is Little Endian.\n");
								}
								else
								{
									PayAttention(
										"The input dungeon file is Big Endian.\n");
								}

								if (!Which.ConvertDungeon())
								{
									PayAttention(
										"Invalid dungeon file.\n");
								}
								else
								{
									System.String DestinationFileName;
									DestinationFileName = JoinPath(GetDir(Arg0), "Converted dungeon.dat");
									if (CompleteFile(Incoming, DestinationFileName))
									{
										PayAttention(""
											+ "The file \n"
											+ DestinationFileName + "\n"
											+ "was successfully created.\n");
									}
								}
							}
						}
						SourceFile.Close();
					} 
					catch (System.Exception e)
					{
						PayAttention(e.ToString() + "\n");
					}
				}
			}
		}
		// 
		static System.Boolean CompleteFile(
			System.IO.Stream FileFrom,
			System.String DestinationFileName)
		{
			try 
			{
				FileFrom.Seek(0, System.IO.SeekOrigin.Begin);
				System.IO.Stream DestinationFile = System.IO.File.Create(DestinationFileName);
				System.IO.BinaryReader Reader = new System.IO.BinaryReader(FileFrom);
				System.IO.BinaryWriter Writer = new System.IO.BinaryWriter(DestinationFile);
				Writer.Write(Reader.ReadBytes((int)FileFrom.Length));
				Reader.Close();
				Writer.Close();
				DestinationFile.Close();
				return true;
			} 
			catch (System.Exception)
			{
				PayAttention(""
					+ "Unable to create the destination file: " + DestinationFileName + "\n");
			}
			return false;
		}
		// 
		static System.String GetDir(
			System.String X)
		{
			int i = X.LastIndexOf('\\');
			if (i != -1)
				return X.Substring(0, i + 1);
			return X;
		}
		// 
		static System.String JoinPath(
			System.String Dir, System.String File)
		{
			if (Dir.LastIndexOf('\\') != Dir.Length - 1)
				Dir += '\\';
			return Dir + File;
		}
		// 
		static void PayAttention(
			System.String Message)
		{
			System.Console.Write(
				Message + "--- Hit Enter to continue ---");
			System.Console.ReadLine();
		}
	}
}
