using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CharaObjConv
{
	class Program
	{
		static void XorFF(byte[] bytes, int count)
		{
			for (var i = 0; i < count; i++)
				bytes[i] ^= 0xff;
		}

		static void MergeObjs(string infolder)
		{
			foreach (var path in Directory.EnumerateFiles(infolder, "*.txt"))
			{
				var strings = File.ReadAllLines(path);

				var infile = Path.Combine(infolder, Path.GetFileNameWithoutExtension(path) + ".obj");
				var file = File.ReadAllBytes(infile);

				Console.WriteLine(infile);

				var lookuplength = BitConverter.ToInt32(file, file.Length - 4);
				var extralength = BitConverter.ToInt32(file, file.Length - 8);
				var stringslength = file.Length - extralength - (lookuplength * 4) - 8;

				var stringoffset = lookuplength * 4;
				var extraoffset = file.Length - extralength - 8;

				//Console.WriteLine(string.Format("{0} {1} {2}", extralength, lookuplength, stringslength));

				XorFF(file, lookuplength * 4 + stringslength);

				var inputoffsets = new List<int>();
				var inputlookup = new List<int>();

				for(var i = 0; i < lookuplength; i++)
					inputlookup.Add(BitConverter.ToInt32(file, i * 4));

				var o = 0;
				
				for (var i = 0; i < stringslength; i += 2)
				{
					var b1 = file[stringoffset + i];
					var b2 = file[stringoffset + i + 1];

					if (b1 == 0 && b2 == 0)
					{
						inputoffsets.Add(o);
						o = i + 2;
					}
				}

				//we got what we need, now lets roll

				var outputoffsets = new Dictionary<int, int>();

				var stringarea = new MemoryStream();
				for (var i = 0; i < strings.Length; i++)
				{
					if(i > 0)
						outputoffsets.Add(inputoffsets[i], (int)stringarea.Position);

					var u = Encoding.Unicode.GetBytes(strings[i]);
					stringarea.Write(u, 0, u.Length);
					stringarea.WriteByte(0x00);
					stringarea.WriteByte(0x00);
				}

				var lookuparea = new MemoryStream();
				for (var i = 0; i < lookuplength; i++)
				{
					var offset = inputlookup[i];
					if (outputoffsets.ContainsKey(offset))
						offset = outputoffsets[offset];

					lookuparea.Write(BitConverter.GetBytes(offset), 0, 4);
				}

				var output = new byte[lookuparea.Length + stringarea.Length + extralength + 8];

				Buffer.BlockCopy(lookuparea.ToArray(), 0, output, 0, (int)lookuparea.Length);
				Buffer.BlockCopy(stringarea.ToArray(), 0, output, (int)lookuparea.Length, (int)stringarea.Length);
				Buffer.BlockCopy(file, extraoffset, output, (int)(lookuparea.Length + stringarea.Length), extralength + 8);

				XorFF(output, output.Length - extralength - 8);

				//var outname = Path.Combine(infolder, Path.GetFileNameWithoutExtension(path) + "_t.obj");

				File.WriteAllBytes(infile, output);
			}
		}

		static void ExtractObjs(string infolder)
		{
			foreach (var path in Directory.EnumerateFiles(infolder, "*.obj"))
			{
				Console.WriteLine(path);

				var file = File.ReadAllBytes(path);

				var lookuplength = BitConverter.ToInt32(file, file.Length - 4);
				var extralength = BitConverter.ToInt32(file, file.Length - 8);
				var stringslength = file.Length - extralength - (lookuplength * 4) - 8;

				var stringoffset = lookuplength*4;

				//Console.WriteLine(string.Format("{0} {1} {2}", extralength, lookuplength, stringslength));
				
				XorFF(file, lookuplength * 4 + stringslength);

				var blist = new List<byte>();
				var strings = new List<string>();
				var offsets = new List<int>();

				var o = 0;

				for (var i = 0; i < stringslength; i += 2)
				{
					var b1 = file[stringoffset + i];
					var b2 = file[stringoffset + i + 1];

					if (b1 == 0 && b2 == 0)
					{
						strings.Add(Encoding.Unicode.GetString(blist.ToArray()));
						blist.Clear();
						offsets.Add(o);
						o = i + 2;
					}
					else
					{
						blist.Add(b1);
						blist.Add(b2);
					}
				}

				File.WriteAllLines(Path.Combine(infolder, Path.GetFileNameWithoutExtension(path) + ".txt"), strings);

				//break;
			}
		}

		static void Main(string[] args)
		{
			string inputfolder = @"C:\Users\dmcne_000\Downloads\arc_conv\obj";

			if (args.Length != 2)
			{
				Console.WriteLine("Usage: \n To extract, use option '-extract foldername'.\n To merge, use '-merge foldername'.");
				//Console.ReadKey();
				return;
			}

			if (args[0] == "-extract")
			{
				ExtractObjs(args[1]);
				Console.WriteLine("Done");
			}

			if (args[0] == "-merge")
			{
				MergeObjs(args[1]);
				Console.WriteLine("Done");
			}
				
		}
	}
}
