using System;

namespace DM2LLGDATMaker
{
	/// <summary>
	/// Class1 の概要の説明です。
	/// </summary>
	class Class1
	{
		static void HelpMe()
		{
			System.Console.WriteLine("DM2LLGDATMaker {r|w} {GRAPHICS.DAT} {Work Dir}");
		}
		static System.String JoinPath(
			System.String Dir, System.String File
			)
		{
			if (Dir.LastIndexOf('\\') != Dir.Length - 1)
				Dir += '\\';
			return Dir + File;
		}

		/// <summary>
		/// アプリケーションのメイン エントリ ポイントです。
		/// </summary>
		[STAThread]
		static void Main(string[] args)
		{
			if (args.Length < 3)
			{
				HelpMe(); return;
			}
			switch (args[0])
			{
				case "r":
					if (true)
					{
						DM2GDFR pGD = new DM2GDFR(args[1]);
						pGD.Init();
						int iFile = 0;
						System.Text.StringBuilder pMergeInfo = new System.Text.StringBuilder(1024 * 300);
						foreach (BinaryEntry pEntry in pGD.Entries)
						{
							string sFile = iFile.ToString("0000") + ".bin";
							string sFilePath = JoinPath(args[2], sFile);

							System.IO.Stream pFileInto = System.IO.File.Open(sFilePath, System.IO.FileMode.Create);
							pFileInto.Write(pEntry.Binary, 0, pEntry.Binary.Length);
							pFileInto.Close();

							pMergeInfo.AppendFormat("{0}\r\n", sFilePath);

							iFile++;
						}
						string sMergePath = JoinPath(args[2], "Merge.txt");
						System.IO.TextWriter pMergeInto = new System.IO.StreamWriter(sMergePath, false, System.Text.Encoding.Default);
						pMergeInto.Write(pMergeInfo.ToString());
						pMergeInto.Close();
					}
					break;
				case "w":
					if (true)
					{
						string sMergePath = JoinPath(args[2], "Merge.txt");
						System.IO.TextReader pTextIn;
						pTextIn = new System.IO.StreamReader(sMergePath, System.Text.Encoding.Default);
						string s;
						int nEntries = 0;
						while ((s = pTextIn.ReadLine()) != null && s.Length > 0)
							nEntries++;
						pTextIn.Close();
						pTextIn = new System.IO.StreamReader(sMergePath, System.Text.Encoding.Default);
						DM2GDFM pGD = new DM2GDFM(args[1], true, nEntries);
						pGD.Init();
						while ((s = pTextIn.ReadLine()) != null && s.Length > 0)
						{
							System.IO.Stream pFileIn = System.IO.File.OpenRead(s);
							Byte[] pBinary = new Byte[pFileIn.Length];
							pFileIn.Read(pBinary, 0, pBinary.Length);
							BinaryEntry pEntry = new BinaryEntry(pBinary);
							pGD.Add(pEntry);
							pFileIn.Close();
						}
						pGD.Burn();
					}
					break;
			}
		}
	}

	abstract class BinRW
	{
		// 
		System.IO.Stream m_pFileThru;
		// 
		public BinRW(System.IO.Stream pFileThru)
		{
			m_pFileThru = pFileThru;
		}
		// 
		public Byte SureReadByte()
		{
			int x = m_pFileThru.ReadByte();
			if (x < 0) throw (new System.IO.EndOfStreamException());
			return System.Convert.ToByte(x);
		}
		// 
		public abstract System.UInt16 SureReadWord();
		// 
		public abstract System.UInt32 SureReadDWord();
		// 
		public void SureWriteByte(System.Byte x)
		{
			m_pFileThru.WriteByte(x);
		}
		// 
		public abstract void SureWriteWord(System.UInt16 x);
		// 
		public abstract void SureWriteDWord(System.UInt32 x);
	}
	// 
	class BinRWLE : BinRW
	{
		// 
		public BinRWLE(System.IO.Stream pFileThru): base(pFileThru)
		{

		}
		// 
		public override System.UInt16 SureReadWord()
		{
			return System.Convert.ToUInt16(SureReadByte() + SureReadByte() * 256);
		}
		// 
		public override System.UInt32 SureReadDWord()
		{
			return System.Convert.ToUInt32(SureReadWord() + SureReadWord() * 65536);
		}
		// 
		public override void SureWriteWord(System.UInt16 x)
		{
			SureWriteByte(System.Convert.ToByte((x >> 0) & 0xFF));
			SureWriteByte(System.Convert.ToByte((x >> 8) & 0xFF));
		}
		// 
		public override void SureWriteDWord(System.UInt32 x)
		{
			SureWriteWord(System.Convert.ToUInt16((x >> 0) & 0xFFFF));
			SureWriteWord(System.Convert.ToUInt16((x >>16) & 0xFFFF));
		}
	};
	// 
	class BinRWBE : BinRW
	{
		// 
		public BinRWBE(System.IO.Stream pFileThru): base(pFileThru)
		{

		}
		// 
		public override System.UInt16 SureReadWord()
		{
			return System.Convert.ToUInt16(SureReadByte() * 256 + SureReadByte());
		}
		// 
		public override System.UInt32 SureReadDWord()
		{
			return System.Convert.ToUInt32(SureReadWord() * 65536 + SureReadWord());
		}
		// 
		public override void SureWriteWord(System.UInt16 x)
		{
			SureWriteByte(System.Convert.ToByte((x >> 8) & 0xFF));
			SureWriteByte(System.Convert.ToByte((x >> 0) & 0xFF));
		}
		// 
		public override void SureWriteDWord(System.UInt32 x)
		{
			SureWriteWord(System.Convert.ToUInt16((x >>16) & 0xFFFF));
			SureWriteWord(System.Convert.ToUInt16((x >> 0) & 0xFFFF));
		}
	};

	// 
	class BinaryEntry
	{
		// 
		private Byte[] m_pBinary;
		// 
		public BinaryEntry(Byte[] pBinary)
		{
			m_pBinary = pBinary;
		}
		// 
		public Byte[] Binary
		{
			get { return m_pBinary; }
		}
	}
	// 
	class DM2GDFR
	{
		// 
		BinaryEntry[] m_pEntries;
		// 
		System.IO.Stream m_pFileIn;
		// 
		public DM2GDFR(string sDAT)
		{
			m_pFileIn = System.IO.File.OpenRead(sDAT);
		}
		// 
		public void Init()
		{
			int nSign = m_pFileIn.ReadByte() + m_pFileIn.ReadByte() * 256;
			BinRW pBinIn;
			if (nSign == 0x8005)
				pBinIn = new BinRWLE(m_pFileIn);
			else if (nSign == 0x0580)
				pBinIn = new BinRWBE(m_pFileIn);
			else
				throw (new System.ApplicationException("Invalid GRAPHICS.DAT"));
			int nEntries = pBinIn.SureReadWord();
			int iEntry;
			int[] nEntryLength = new int[nEntries];
			for (iEntry = 0; iEntry < nEntries; iEntry++)
			{
				if (iEntry == 0)
					nEntryLength[iEntry] = System.Convert.ToInt32(pBinIn.SureReadDWord());
				else
					nEntryLength[iEntry] = System.Convert.ToInt32(pBinIn.SureReadWord());
			}
			m_pEntries = new BinaryEntry[nEntries];
			for (iEntry = 0; iEntry < nEntries; iEntry++)
			{
				int nLength = nEntryLength[iEntry];
				Byte[] pBinary = new Byte[nLength];
				m_pFileIn.Read(pBinary, 0, nLength);
				m_pEntries[iEntry] = new BinaryEntry(pBinary);
			}
		}
		// 
		public BinaryEntry[] Entries
		{
			get { return m_pEntries; }
		}
	}
	// 
	class DM2GDFM
	{
		// 
		System.Collections.ArrayList m_pEntries;
		// 
		System.IO.Stream m_pFileInto;
		// 
		BinRW m_pBinInto;
		// 
		bool m_fLittleEndian;
		// 
		public DM2GDFM(string sDAT, bool fLittleEndian, int nCapacity)
		{
			m_pFileInto = System.IO.File.Open(sDAT, System.IO.FileMode.Create);
			m_fLittleEndian = fLittleEndian;
			m_pEntries = new System.Collections.ArrayList(nCapacity);
		}
		// 
		public void Init()
		{
			if (m_fLittleEndian)
			{
				m_pBinInto = new BinRWLE(m_pFileInto);
				m_pBinInto.SureWriteWord(0x8005);
			}
			else
			{
				m_pBinInto = new BinRWBE(m_pFileInto);
				m_pBinInto.SureWriteWord(0x0580);
			}
		}
		// 
		public void Add(BinaryEntry pEntry)
		{
			m_pEntries.Add(pEntry);
		}
		// 
		public void Burn()
		{
			int iEntry;
			int nEntries = m_pEntries.Count;
			m_pBinInto.SureWriteWord(System.Convert.ToUInt16(nEntries));
			for (iEntry = 0; iEntry < nEntries; iEntry++)
			{
				BinaryEntry pEntry = GetEntry(iEntry);
				if (iEntry == 0)
					m_pBinInto.SureWriteDWord(System.Convert.ToUInt32(pEntry.Binary.Length));
				else
					m_pBinInto.SureWriteWord(System.Convert.ToUInt16(pEntry.Binary.Length));
			}
			for (iEntry = 0; iEntry < nEntries; iEntry++)
			{
				BinaryEntry pEntry = GetEntry(iEntry);
				m_pFileInto.Write(pEntry.Binary, 0, pEntry.Binary.Length);
			}
		}
		// 
		public BinaryEntry GetEntry(int i)
		{
			return (BinaryEntry)m_pEntries[i];
		}
	}
}
