using GameBuilder.Pops;
using GameBuilder.Psp;
using Li.Progress;
using PspCrypto;
using Vita.PsvImgTools;

namespace LibChovy
{
    public class ChovySign : ProgressTracker
    {

        private void onProgress(ProgressInfo inf)
        {
            updateProgress(inf.Done, inf.Remain, inf.CurrentProcess);
        }

        private void createPSP(PspParameters parameters)
        {
            using(NpUmdImg img = new NpUmdImg(parameters.DrmInfo, parameters.Umd, parameters.Compress))
            {
                img.PatchSfo();
                using (PbpBuilder pbpBuilder = new PbpBuilder(parameters.Umd.DataFiles["PARAM.SFO"], parameters.Umd.DataFiles["ICON0.PNG"], parameters.Umd.DataFiles["ICON1.PMF"], parameters.Umd.DataFiles["PIC0.PNG"], parameters.Umd.DataFiles["PIC1.PNG"], parameters.Umd.DataFiles["SND0.AT3"], img, 1))
                {
                    pbpBuilder.RegisterCallback(onProgress);
                    pbpBuilder.CreatePsarAndPbp();
                    pbpBuilder.PbpStream.Seek(0x00, SeekOrigin.Begin);

                    byte[] ebootsig = new byte[0x200];
                    SceNpDrm.KsceNpDrmEbootSigGenPsp(pbpBuilder.PbpStream, ebootsig, parameters.FirmwareVersion);

                    if (!parameters.CreatePsvImg)
                    {
                        File.WriteAllBytes(Path.Combine(parameters.OutputFolder, "__sce_ebootpbp"), ebootsig.ToArray());
                        pbpBuilder.WritePbpToFile(Path.Combine(parameters.OutputFolder, "EBOOT.PBP"));
                    }
                    else
                    {
                        createPsvImg(parameters.OutputFolder, parameters.Umd.DiscId, parameters.Umd.DataFiles["PARAM.SFO"], parameters.Umd.DataFiles["ICON0.PNG"], pbpBuilder, parameters.DrmRif, ebootsig, parameters.Account.CmaKey);
                    }
                }
            }
        }

        private void createPOPS(PopsParameters parameters)
        {

            Sfo psfo = new Sfo();
            psfo.AddKey("BOOTABLE", 1, 4);
            psfo.AddKey("CATEGORY", "ME", 4);
            psfo.AddKey("DISC_ID", parameters.FirstDisc.DiscId, 16);
            psfo.AddKey("DISC_VERSION", "1.00", 8);
            psfo.AddKey("LICENSE", "Chovy-Sign is licensed under the GPLv3, And was made possible by SquallATF and Li.", 512);
            psfo.AddKey("PARENTAL_LEVEL", 0, 4);
            psfo.AddKey("PSP_SYSTEM_VER", "6.61", 8);
            psfo.AddKey("REGION", 32768, 4);
            psfo.AddKey("TITLE", parameters.Name, 128);
            byte[] sfo = psfo.WriteSfo();

            PopsImg img;
            if (parameters.MultiDisc)
                img = new PsTitleImg(parameters.DrmInfo, parameters.Discs);
            else
                img = new PsIsoImg(parameters.DrmInfo, parameters.FirstDisc);

            using (PbpBuilder pbpBuilder = new PbpBuilder(sfo, parameters.Icon0, null, parameters.Pic0, parameters.Pic1, null, img, 0))
            {
                pbpBuilder.RegisterCallback(onProgress);
                pbpBuilder.CreatePsarAndPbp();
                pbpBuilder.PbpStream.Seek(0x00, SeekOrigin.Begin);

                byte[] ebootsig = new byte[0x200];
                SceNpDrm.KsceNpDrmEbootSigGenPs1(pbpBuilder.PbpStream, ebootsig, parameters.FirmwareVersion);

                if (!parameters.CreatePsvImg)
                {
                    File.WriteAllBytes(Path.Combine(parameters.OutputFolder, "__sce_ebootpbp"), ebootsig.ToArray());
                    pbpBuilder.WritePbpToFile(Path.Combine(parameters.OutputFolder, "EBOOT.PBP"));
                }
                else
                {
                    createPsvImg(parameters.OutputFolder, parameters.FirstDisc.DiscId, sfo, parameters.Icon0, pbpBuilder, parameters.DrmRif, ebootsig, parameters.Account.CmaKey);
                }
            }
        }

        private void createPsvImg(string outputFolder, string discId,
                                  byte[] sfo, byte[] icon0, 
                                  PbpBuilder pbp, NpDrmRif license, byte[] sig,
                                  byte[] cmaKey)
        {
            // create GAME.PSVIMG
            pbp.PbpStream.Seek(0x00, SeekOrigin.Begin);

            string gameFolder = Path.Combine(outputFolder, "game");
            string licenseFolder = Path.Combine(outputFolder, "license");
            string sceSysFolder = Path.Combine(outputFolder, "sce_sys");

            if (!Directory.Exists(gameFolder)) Directory.CreateDirectory(gameFolder);
            if (!Directory.Exists(licenseFolder)) Directory.CreateDirectory(licenseFolder);
            if (!Directory.Exists(sceSysFolder)) Directory.CreateDirectory(sceSysFolder);


            using (FileStream gamePsvimg = File.Open(Path.Combine(gameFolder, "game.psvimg"), FileMode.Create, FileAccess.ReadWrite))
            {
                PSVIMGBuilder psvImg = new PSVIMGBuilder(gamePsvimg, cmaKey);
                psvImg.RegisterCallback(onProgress);
                psvImg.AddFile(pbp.PbpStream, "ux0:pspemu/temp/game/PSP/GAME/" + discId, "/EBOOT.PBP");
                psvImg.AddFile(sig, "ux0:pspemu/temp/game/PSP/GAME/" + discId, "/__sce_ebootpbp");
                long contentSize = psvImg.Finish();

                // create GAME.PSVMD
                using (FileStream gamePsvmd = File.Open(Path.Combine(gameFolder, "game.psvmd"), FileMode.Create, FileAccess.ReadWrite))
                    PSVMDBuilder.CreatePsvmd(gamePsvmd, gamePsvimg, contentSize, "game", cmaKey);
            }

            // create LICENSE.PSVIMG
            using (FileStream gamePsvimg = File.Open(Path.Combine(licenseFolder, "license.psvimg"), FileMode.Create, FileAccess.ReadWrite))
            {
                PSVIMGBuilder psvImg = new PSVIMGBuilder(gamePsvimg, cmaKey);
                psvImg.RegisterCallback(onProgress);
                psvImg.AddFile(license.Rif, "ux0:pspemu/temp/game/PSP/LICENSE", "/" + license.ContentId + ".rif");
                long contentSize = psvImg.Finish();

                // create LICENSE.PSVMD
                using (FileStream gamePsvmd = File.Open(Path.Combine(licenseFolder, "license.psvmd"), FileMode.Create, FileAccess.ReadWrite))
                    PSVMDBuilder.CreatePsvmd(gamePsvmd, gamePsvimg, contentSize, "license", cmaKey);

            }

            // write SCE_SYS
            File.WriteAllBytes(Path.Combine(sceSysFolder, "param.sfo"), sfo);
            File.WriteAllBytes(Path.Combine(sceSysFolder, "icon0.png"), icon0);

        }

        public void Go(ChovySignParameters parameters)
        {

            SceNpDrm.Aid = parameters.DrmRif.AccountId;

            if (!Directory.Exists(parameters.OutputFolder))
                Directory.CreateDirectory(parameters.OutputFolder);

            if (parameters.Type == ChovyTypes.PSP)
                createPSP((PspParameters)parameters);
            else
                createPOPS((PopsParameters)parameters);
        }
    }
}
