using System;
using System.Collections;
using System.IO;

namespace rshw2sst
{
    public class Program
    {
        static bool usingRSHW = false;
        static int charaIndex = 0;

        public static void Main(string[] args)
        {
            Console.WriteLine("RSHW and CSHW Data Converter");
            if (args[0] == "help")
            {
                Console.WriteLine("Usage: rshw2sst <file path> <character> <output directory>\n"
                    + "This will output a SST Showtape for 1 Cyberamic Character\n"
                    + "If an RSHW file is used, it will convert the bits according to Rosetta\n"
                );
            }
            if (!File.Exists(args[0]))
            {
                Console.WriteLine("FATAL: Specified file does not exist.");
                return;
            }
            switch (Path.GetExtension(args[0]).ToLower())
            {
                case ".rshw":
                    usingRSHW = true;
                    break;
                case ".cshw":
                    usingRSHW = false;
                    break;
                default:
                    Console.WriteLine("FATAL: Only RSHW and CSHW files are supported.");
                    return;
            }
            string chara = args[1].ToLower();
            if (chara.Contains("chuck") || chara.Contains("rolfe")) charaIndex = 0;
            else if (chara.Contains("helen") || chara.Contains("mitzi")) charaIndex = 1;
            else if (chara.Contains("munch") || chara.Contains("fatz")) charaIndex = 2;
            else if (chara.Contains("jasper") || chara.Contains("beach")) charaIndex = 3;
            else if (chara.Contains("pasqually") || chara.Contains("dook")) charaIndex = 4;
            else if (chara.Contains("bella") || chara.Contains("billy"))
            {
                Console.WriteLine("you wish!!!!");
                return;
            }
            else
            {
                Console.WriteLine("FATAL: Invalid character.");
                return;
            }
            if (!Directory.Exists(args[2])) Directory.CreateDirectory(args[2]);
            RSHWFile file = RSHWLoader.Load(args[0]);
            if (file.signalData == null)
            {
                Console.WriteLine("FATAL: This file contains no signal data.");
                return;
            }
            if (file.audioData != null) File.WriteAllBytes(args[2] + "/audio_out.wav", file.audioData);
            if (file.videoData != null) File.WriteAllBytes(args[2] + "/video_out.mp4", file.videoData);
            Console.WriteLine("Wrote out audio and video data.");

            List<BitArray> rshwBits = new List<BitArray>();
            int countlength = 0;
            if (file.signalData[0] != 0)
            {
                countlength = 1;
                BitArray bit = new BitArray(300);
                rshwBits.Add(bit);
            }
            for (int i = 0; i < file.signalData.Length; i++)
            {
                if (file.signalData[i] == 0)
                {
                    countlength += 1;
                    BitArray bit = new BitArray(300);
                    rshwBits.Add(bit);
                }
                else
                {
                    rshwBits[countlength - 1].Set(file.signalData[i], true);
                }
            }
            Console.WriteLine("Loaded RSHW signal data.");

            List<byte> writeOut = new List<byte>();
            foreach (BitArray bits in rshwBits)
            {
                byte frameByte = 0;
                Dictionary<int, byte>[] mapping = RosettaR12;
                if (usingRSHW) mapping = Rosetta3St;
                foreach (KeyValuePair<int, byte> movement in mapping[charaIndex])
                {
                    if (bits.Get(movement.Key)) frameByte += movement.Value;
                }
                writeOut.Add(frameByte);
            }
            File.WriteAllBytes(args[2] + "/signals_out.sts", writeOut.ToArray());
            Console.WriteLine("Wrote out signal data.");

            File.WriteAllText(args[2] + "/manifest.ini", $"; Exported by RSHW2SST\nname={Path.GetFileNameWithoutExtension(args[0])} {args[1]}\nvideo=video_out.mp4\naudio=audio_out.wav\ndata=signals_out.sts\nframes-per-second=60\nbits-per-frame=8");
            Console.WriteLine("Wrote out manifest.");
            if (file.videoData == null) Console.WriteLine("Warning: Video data was blank, you will need to add the file manually.");
            Console.WriteLine("Complete!");
        }

        public static Dictionary<int, byte>[] Rosetta3St =
        {
            new Dictionary<int, byte>
            { {1, 1}, {8, 2}, {7, 4}, {6, 8}, {5, 16}, {4, 32}, {2, 64}, {19, 128} }, // chuck
            new Dictionary<int, byte>
            { {185, 1}, {180, 2}, {179, 4}, {178, 8}, {184, 16}, {183, 32}, {181, 64}, {169, 128} }, // helen
            new Dictionary<int, byte>
            { {45, 1}, {55, 2}, {54, 4}, {44, 8}, {43, 16}, {41, 32}, {60, 64}, {59, 128} }, // munch
            new Dictionary<int, byte>
            { {166, 1}, {158, 2}, {157, 4}, {156, 8}, {153, 16}, {152, 32}, {151, 64}, {163, 128} }, // jasper
            new Dictionary<int, byte>
            { {30, 1}, {21, 2}, {25, 4}, {29, 8}, {28, 16}, {26, 32}, {31, 64}, {35, 128} } // pasqually
        };

        public static Dictionary<int, byte>[] RosettaR12 =
        {
            new Dictionary<int, byte>
            { {1, 1}, {4, 2}, {3, 4}, {2, 8}, {5, 16}, {8, 32}, {6, 64}, {7, 128} }, // chuck
            new Dictionary<int, byte>
            { {65, 1}, {68, 2}, {67, 4}, {66, 8}, {69, 16}, {72, 32}, {70, 64}, {71, 128} }, // helen
            new Dictionary<int, byte>
            { {49, 1}, {51, 2}, {50, 4}, {53, 8}, {56, 16}, {54, 32}, {55, 64}, {52, 128} }, // munch
            new Dictionary<int, byte>
            { {17, 1}, {20, 2}, {19, 4}, {18, 8}, {21, 16}, {24, 32}, {22, 64}, {23, 128} }, // jasper
            new Dictionary<int, byte>
            { {33, 1}, {35, 2}, {34, 4}, {37, 8}, {40, 16}, {38, 32}, {39, 64}, {36, 128} } // pasqually
        };
    }
}