public void UpdateMission(ZkDataContext db, Mission mission, SpringScanner scanner)
 {
     var file = mission.Mutator.ToArray();
     var targetPath = Path.Combine(scanner.SpringPaths.WritableDirectory, "games", mission.SanitizedFileName);
     File.WriteAllBytes(targetPath, file);
     
     var modInfo = scanner.unitSync.GetResourceFromFileName(targetPath) as Mod;
     File.Delete(targetPath);
     UpdateMission(db, mission, modInfo);
 }
        public void UpdateMission(ZkDataContext db, Mission mission, SpringPaths paths, string engine)
        {
            var file = mission.Mutator.ToArray();
            var targetPath = Path.Combine(paths.WritableDirectory, "games", mission.SanitizedFileName);
            File.WriteAllBytes(targetPath, file);

            Mod modInfo;
            using (var unitsync = new UnitSync(paths, engine))
            {
                modInfo = unitsync.GetResourceFromFileName(targetPath) as Mod;
            }

            File.Delete(targetPath);
            UpdateMission(db, mission, modInfo);
        }
	    public void SendMission(Mission mission, List<MissionSlot> slots, string author, string password, Mod modInfo)
		{
            if (mission == null) throw new ApplicationException("Mission is null");

			Account acc = null;
			var db = new ZkDataContext();
			if (Debugger.IsAttached) acc = db.Accounts.SingleOrDefault(x => x.Name == "Testor303");
			else acc = AuthServiceClient.VerifyAccountPlain(author, password);

		    if (acc == null)
		    {
                Trace.TraceWarning("Invalid login attempt for {0}", author);
                System.Threading.Thread.Sleep(new Random().Next(2000));
                throw new ApplicationException("Cannot verify user account");
		    }


            Mission prev = db.Missions.SingleOrDefault(x => x.MissionID == mission.MissionID || (x.Name == mission.Name && x.AccountID == acc.AccountID)); // previous mission by id or name + account
			if (prev == null && db.Missions.Any(x =>x.Name == mission.Name)) throw new ApplicationException("Mission name must be unique");
			var map = db.Resources.SingleOrDefault(x => x.InternalName == mission.Map && x.TypeID == ZkData.ResourceType.Map);
			if (map == null) throw new ApplicationException("Map name is unknown");
			var mod = db.Resources.SingleOrDefault(x => x.InternalName == mission.Mod && x.TypeID == ZkData.ResourceType.Mod);
			if (mod == null) throw new ApplicationException("Mod name is unknown");
			//if (db.Resources.Any(x => x.InternalName == mission.Name && x.MissionID != null)) throw new ApplicationException("Name already taken by other mod/map");

            modInfo.MissionMap = mission.Map;

			if (prev != null)
			{
				if (prev.AccountID != acc.AccountID && !acc.IsZeroKAdmin) throw new ApplicationException("Invalid author or password");
				prev.Description = mission.Description;
                prev.DescriptionStory = mission.DescriptionStory;
				prev.Mod = mission.Mod;
				prev.Map = mission.Map;
				prev.Name = mission.Name;
				prev.ScoringMethod = mission.ScoringMethod;
				prev.ModRapidTag = mission.ModRapidTag;
				prev.ModOptions = mission.ModOptions;
				prev.Image = mission.Image;
				prev.MissionEditorVersion = mission.MissionEditorVersion;
				prev.SpringVersion = mission.SpringVersion;
				prev.Revision++;
				prev.Mutator = mission.Mutator;
                prev.ForumThread.Title = mission.Name;
				mission = prev;
			}
			else
			{
				mission.CreatedTime = DateTime.UtcNow;
                mission.ForumThread = new ForumThread() { Title = mission.Name, ForumCategory = db.ForumCategories.FirstOrDefault(x=>x.ForumMode==ForumMode.Missions), CreatedAccountID = acc.AccountID, LastPostAccountID= acc.AccountID };
                mission.ForumThread.UpdateLastRead(acc.AccountID, true);
				db.Missions.InsertOnSubmit(mission);
			}
			mission.AccountID = acc.AccountID;
			mission.Script = Regex.Replace(mission.Script, "GameType=([^;]+);", (m) => { return string.Format("GameType={0};", mission.NameWithVersion); });
			mission.MinHumans = slots.Count(x => x.IsHuman && x.IsRequired);
			mission.MaxHumans = slots.Count(x => x.IsHuman);
			mission.ModifiedTime = DateTime.UtcNow;
			mission.IsDeleted = true;
			mission.IsCoop = slots.Where(x => x.IsHuman).GroupBy(x => x.AllyID).Count() == 1;

	        db.SaveChanges();

	        var updater = new MissionUpdater();
            updater.UpdateMission(db, mission, modInfo);

			mission.IsDeleted = false;
	        db.SaveChanges();
		}
        public void UpdateMission(ZkDataContext db, Mission mission, Mod modInfo) {
            var file = mission.Mutator.ToArray();
            var tempName = Path.GetTempFileName() + ".zip";
            File.WriteAllBytes(tempName, file);

            using (var zf = new ZipFile(tempName))
            {
                zf.UpdateEntry("modinfo.lua", Encoding.UTF8.GetBytes(GetModInfo(mission.NameWithVersion, mission.Mod, mission.Name, "ZK")));    // FIXME hardcoded crap
                FixScript(mission, zf, "script.txt");
                var script = FixScript(mission, zf, GlobalConst.MissionScriptFileName);
                modInfo.MissionScript = script;
                //modInfo.ShortName = mission.Name;
                modInfo.Name = mission.NameWithVersion;
                zf.Save();
            }
            mission.Mutator = File.ReadAllBytes(tempName);
            mission.Script = Regex.Replace(mission.Script, "GameType=([^;]+);", (m) => { return string.Format("GameType={0};", mission.NameWithVersion); });
            
            File.Delete(tempName);
            
            var resource = db.Resources.FirstOrDefault(x => x.MissionID == mission.MissionID); 
            if (resource == null)
            {
                resource = new Resource() { DownloadCount = 0, TypeID = ZkData.ResourceType.Mod };
                db.Resources.Add(resource);
            }
            resource.InternalName = mission.NameWithVersion;
            resource.MissionID = mission.MissionID;

            resource.ResourceDependencies.Clear();
            resource.ResourceDependencies.Add(new ResourceDependency() { NeedsInternalName = mission.Map });
            resource.ResourceDependencies.Add(new ResourceDependency() { NeedsInternalName = mission.Mod });
            resource.ResourceContentFiles.Clear();
            

            // generate torrent
            var tempFile = Path.Combine(Path.GetTempPath(), mission.SanitizedFileName);
            File.WriteAllBytes(tempFile, mission.Mutator.ToArray());
            var creator = new TorrentCreator();
            creator.Path = tempFile;
            var torrentStream = new MemoryStream();
            creator.Create(torrentStream);
            try
            {
                File.Delete(tempFile);
            }
            catch { }

            var md5 = Hash.HashBytes(mission.Mutator.ToArray()).ToString();
            resource.ResourceContentFiles.Add(new ResourceContentFile()
            {
                FileName = mission.SanitizedFileName,
                Length = mission.Mutator.Length,
                LinkCount = 1,
                Links = string.Format(MissionFileUrl, mission.MissionID),
                Md5 = md5
            });


            var basePath = GlobalConst.SiteDiskPath + @"\resources\";
            File.WriteAllBytes(string.Format(@"{2}\{0}_{1}.torrent", resource.InternalName.EscapePath(), md5, basePath), torrentStream.ToArray());
            
            File.WriteAllBytes(string.Format(@"{1}\{0}.metadata.xml.gz", resource.InternalName.EscapePath(), basePath),
                                   MetaDataCache.SerializeAndCompressMetaData(modInfo));
            
            File.WriteAllBytes(string.Format(GlobalConst.SiteDiskPath + @"\img\missions\{0}.png", mission.MissionID, basePath), mission.Image.ToArray());

        }
 static string FixScript(Mission mission, ZipFile zf, string scriptName)
 {
     var ms = new MemoryStream();
     zf[scriptName].Extract(ms);
     var script = Encoding.UTF8.GetString(ms.ToArray());
     script = Regex.Replace(script, "GameType=([^;]+);", (m) => { return string.Format("GameType={0};", mission.NameWithVersion); });
     zf.UpdateEntry(scriptName, Encoding.UTF8.GetBytes(script));
     return script;
 }
        public static void ProgressCampaign(ZkDataContext db, Account acc, Mission mission, bool completeNext = false, string missionVars = "")
        {
            CampaignPlanet planet = db.CampaignPlanets.FirstOrDefault(p => p.MissionID == mission.MissionID);
            if (planet != null)
            {
                AccountCampaignProgress progress = acc.AccountCampaignProgress.FirstOrDefault(x => x.PlanetID == planet.PlanetID && x.CampaignID == planet.CampaignID);
                bool alreadyCompleted = false;
                int accountID = acc.AccountID;
                int campID = planet.CampaignID;
                Campaign camp = planet.Campaign;
                List<CampaignPlanet> unlockedPlanets = new List<CampaignPlanet>();
                List<CampaignJournal> unlockedJournals = new List<CampaignJournal>();

                // start with processing the mission vars, if there are any
                byte[] missionVarsAsByteArray = System.Convert.FromBase64String(missionVars);
                string missionVarsDecoded = System.Text.Encoding.UTF8.GetString(missionVarsAsByteArray);
                foreach (string kvpRaw in missionVarsDecoded.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
                {
                    string kvpRaw2 = kvpRaw.Trim();
                    string key = "", value = "";
                    string[] kvpSplit = kvpRaw2.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries);
                    if (kvpSplit.Length == 2)
                    {
                        key = kvpSplit[0].Trim();
                        value = kvpSplit[1].Trim();
                    }
                    else
                    {
                        throw new Exception("Invalid key-value pair in decoded mission vars: " + missionVarsDecoded);
                    }
                    if (!(string.IsNullOrEmpty(key) || string.IsNullOrEmpty(value)))
                    {
                        CampaignVar cv = camp.CampaignVars.First(x => x.KeyString == key);
                        AccountCampaignVar acv = acc.AccountCampaignVars.FirstOrDefault(x => x.CampaignID == campID && x.VarID == cv.VarID);
                        if (acv == null)
                        {
                            db.AccountCampaignVars.InsertOnSubmit(new AccountCampaignVar() { AccountID = accountID, CampaignID = campID, VarID = cv.VarID, Value = value });
                        }
                        else acv.Value = value;
                    }
                }

                //reload DB - this allows the vars submitted this session to be used by the following code
                db.SaveChanges();
                db = new ZkDataContext();
                acc = db.Accounts.First(x => x.AccountID == accountID);

                // now we unlock planets and journal entries
                // first mark this planet as completed - but only if it's already unlocked
                if (progress != null)
                {
                    alreadyCompleted = progress.IsCompleted;
                }
                else if (planet.StartsUnlocked)
                {
                    progress = new AccountCampaignProgress() { AccountID = accountID, CampaignID = campID, PlanetID = planet.PlanetID, IsCompleted = false, IsUnlocked = true };
                    db.AccountCampaignProgress.InsertOnSubmit(progress);
                }

                if (progress != null && planet.IsUnlocked(accountID))
                {
                    progress.IsCompleted = true;


                    // unlock planets made available by completing this one
                    var links = camp.CampaignLinks.Where(x => x.UnlockingPlanetID == planet.PlanetID);
                    foreach (CampaignLink link in links)
                    {
                        CampaignPlanet toUnlock = link.PlanetToUnlock;
                        bool proceed = true;
                        var requiredVars = toUnlock.CampaignPlanetVars;
                        if (requiredVars.Count() == 0) proceed = true;
                        else
                        {
                            foreach (CampaignPlanetVar variable in requiredVars)
                            {
                                AccountCampaignVar accountVar = acc.AccountCampaignVars.FirstOrDefault(x => x.CampaignID == campID && x.VarID == variable.RequiredVarID);
                                if (!(accountVar != null && accountVar.Value == variable.RequiredValue))
                                {
                                    proceed = false;
                                    break;  // failed to meet var requirement, stop here
                                }
                            }
                        }

                        if (proceed)    // met requirements for unlocking planet
                        {
                            AccountCampaignProgress progress2 = toUnlock.AccountCampaignProgress.FirstOrDefault(x => x.CampaignID == campID && x.AccountID == accountID);
                            if (progress2 == null)
                            {
                                progress2 = new AccountCampaignProgress() { AccountID = accountID, CampaignID = campID, PlanetID = toUnlock.PlanetID, IsCompleted = completeNext, IsUnlocked = true };
                                db.AccountCampaignProgress.InsertOnSubmit(progress2);
                                unlockedPlanets.Add(toUnlock);
                            }
                            else if (!progress2.IsUnlocked)
                            {
                                progress2.IsUnlocked = true;
                                unlockedPlanets.Add(toUnlock);
                            }
                        }
                    }
                }
                // unlock journals
                var journalsWithVars = db.CampaignJournals.Where(x => x.CampaignID == campID && x.CampaignJournalVars.Any());
                foreach (CampaignJournal journal in journalsWithVars)
                {
                    bool proceed = true;
                    var requiredVars = journal.CampaignJournalVars.Where(x => x.CampaignID == campID).ToList();
                    foreach (CampaignJournalVar variable in requiredVars)
                    {
                        AccountCampaignVar accountVar = acc.AccountCampaignVars.FirstOrDefault(x => x.CampaignID == campID && x.VarID == variable.RequiredVarID);
                        if (!(accountVar != null && accountVar.Value == variable.RequiredValue))
                        {
                            proceed = false;
                            break;  // failed to meet var requirement, stop here
                        }
                    }

                    if (proceed)    // met requirements for unlocking journal
                    {
                        AccountCampaignJournalProgress jp = journal.AccountCampaignJournalProgress.FirstOrDefault(x => x.AccountID == accountID);
                        if (jp == null)
                        {
                            jp = new AccountCampaignJournalProgress() { AccountID = accountID, CampaignID = campID, JournalID = journal.JournalID, IsUnlocked = true };
                            db.AccountCampaignJournalProgress.InsertOnSubmit(jp);
                            unlockedJournals.Add(journal);
                        }
                        else if (!jp.IsUnlocked)
                        {
                            jp.IsUnlocked = true;
                            unlockedJournals.Add(journal);
                        }
                    }
                }

                if (!alreadyCompleted)
                {
                    System.Console.WriteLine("Planet completed: {0}", planet);
                    foreach (CampaignJournal journal in db.CampaignJournals.Where(x => x.CampaignID == campID && x.CampaignPlanet.PlanetID == planet.PlanetID && x.UnlockOnPlanetCompletion))
                    {
                        unlockedJournals.Add(journal);
                    }
                }
                foreach (CampaignPlanet unlocked in unlockedPlanets)
                {
                    System.Console.WriteLine("Planet unlocked: {0}", unlocked);
                    foreach (CampaignJournal journal in db.CampaignJournals.Where(x => x.CampaignID == campID && x.CampaignPlanet.PlanetID == unlocked.PlanetID && x.UnlockOnPlanetUnlock))
                    {
                        unlockedJournals.Add(journal);
                    }
                }
                foreach (CampaignJournal uj in unlockedJournals)
                {
                    System.Console.WriteLine("{1} - Journal entry unlocked: {0}", uj, uj.CampaignPlanet);
                }
                db.SaveChanges();
            }
        }
        public void UpdateMission(ZkDataContext db, Mission mission, Mod modInfo) {
            var file = mission.Mutator.ToArray();
            var tempName = Path.GetTempFileName() + ".zip";
            File.WriteAllBytes(tempName, file);

            

            using (var zf = ZipFile.Open(tempName, ZipArchiveMode.Update))
            {
                var modinfoEntry = zf.GetEntry("modinfo.lua");
                modinfoEntry.Delete();
                modinfoEntry = zf.CreateEntry("modinfo.lua");
                WriteZipArchiveEntry(modinfoEntry, GetModInfo(mission.NameWithVersion, mission.ModRapidTag, mission.Name, "ZK"));
                FixScript(mission, zf, "script.txt");
                var script = FixScript(mission, zf, GlobalConst.MissionScriptFileName);
                modInfo.MissionScript = script;
                //modInfo.ShortName = mission.Name;
                modInfo.Name = mission.NameWithVersion;
            }
            mission.Mutator = File.ReadAllBytes(tempName);
            if (string.IsNullOrEmpty(mission.Script)) mission.Script = " "; // tweak for silly update validation
            mission.Script = Regex.Replace(mission.Script, "GameType=([^;]+);", (m) => $"GameType={mission.NameWithVersion};");
            
            File.Delete(tempName);
            
            var resource = db.Resources.FirstOrDefault(x => x.MissionID == mission.MissionID); 
            if (resource == null)
            {
                resource = new Resource() { DownloadCount = 0, TypeID = ZkData.ResourceType.Mod };
                db.Resources.Add(resource);
            }
            resource.InternalName = mission.NameWithVersion;
            resource.MissionID = mission.MissionID;

            resource.ResourceDependencies.Clear();
            resource.ResourceDependencies.Add(new ResourceDependency() { NeedsInternalName = mission.Map });
            resource.ResourceDependencies.Add(new ResourceDependency() { NeedsInternalName = mission.Mod });
            resource.ResourceContentFiles.Clear();
            

            // generate torrent
            var tempFile = Path.Combine(Path.GetTempPath(), mission.SanitizedFileName);
            File.WriteAllBytes(tempFile, mission.Mutator.ToArray());
            var creator = new TorrentCreator();
            creator.Path = tempFile;
            var torrentStream = new MemoryStream();
            creator.Create(torrentStream);
            try
            {
                File.Delete(tempFile);
            }
            catch { }

            var md5 = Hash.HashBytes(mission.Mutator.ToArray()).ToString();
            resource.ResourceContentFiles.Add(new ResourceContentFile()
            {
                FileName = mission.SanitizedFileName,
                Length = mission.Mutator.Length,
                LinkCount = 1,
                Links = string.Format(MissionFileUrl, mission.MissionID),
                Md5 = md5
            });


            var basePath = GlobalConst.SiteDiskPath + @"\resources\";
            if (!Directory.Exists(basePath)) Directory.CreateDirectory(basePath);
            File.WriteAllBytes(string.Format(@"{2}\{0}_{1}.torrent", resource.InternalName.EscapePath(), md5, basePath), torrentStream.ToArray());
            
            File.WriteAllBytes(string.Format(@"{1}\{0}.metadata.xml.gz", resource.InternalName.EscapePath(), basePath),
                                   MetaDataCache.SerializeAndCompressMetaData(modInfo));
            
            var imgPath = GlobalConst.SiteDiskPath + @"\img\missions\";
            if (!Directory.Exists(imgPath)) Directory.CreateDirectory(imgPath);
            
            File.WriteAllBytes(string.Format(imgPath + "{0}.png", mission.MissionID, basePath), mission.Image.ToArray());
        }
 static string FixScript(Mission mission, ZipArchive archive, string scriptName)
 {
     string script;
     ZipArchiveEntry entry = archive.GetEntry(scriptName);
     using (StreamReader reader = new StreamReader(entry.Open()))
     {
         script = reader.ReadToEnd();
         script = Regex.Replace(script, "GameType=([^;]+);", (m) => { return string.Format("GameType={0};", mission.NameWithVersion); });
     }
     WriteZipArchiveEntry(entry, script);
     return script;
 }
		private void detach_Missions(Mission entity)
		{
			this.SendPropertyChanging();
			entity.Account = null;
		}
		private void attach_Missions(Mission entity)
		{
			this.SendPropertyChanging();
			entity.Account = this;
		}
 partial void DeleteMission(Mission instance);
 partial void UpdateMission(Mission instance);
 partial void InsertMission(Mission instance);
        public void UpdateMission(ZkDataContext db, Mission mission, Mod modInfo)
        {
            var file     = mission.Mutator.ToArray();
            var tempName = Path.GetTempFileName() + ".zip";

            File.WriteAllBytes(tempName, file);

            using (var zf = new ZipFile(tempName))
            {
                zf.UpdateEntry("modinfo.lua", Encoding.UTF8.GetBytes(GetModInfo(mission.NameWithVersion, mission.Mod, mission.Name, "ZK")));    // FIXME hardcoded crap
                FixScript(mission, zf, "script.txt");
                var script = FixScript(mission, zf, GlobalConst.MissionScriptFileName);
                modInfo.MissionScript = script;
                //modInfo.ShortName = mission.Name;
                modInfo.Name = mission.NameWithVersion;
                zf.Save();
            }
            mission.Mutator = File.ReadAllBytes(tempName);
            mission.Script  = Regex.Replace(mission.Script, "GameType=([^;]+);", (m) => { return(string.Format("GameType={0};", mission.NameWithVersion)); });

            File.Delete(tempName);

            var resource = db.Resources.FirstOrDefault(x => x.MissionID == mission.MissionID);

            if (resource == null)
            {
                resource = new Resource()
                {
                    DownloadCount = 0, TypeID = ZkData.ResourceType.Mod
                };
                db.Resources.Add(resource);
            }
            resource.InternalName = mission.NameWithVersion;
            resource.MissionID    = mission.MissionID;

            resource.ResourceDependencies.Clear();
            resource.ResourceDependencies.Add(new ResourceDependency()
            {
                NeedsInternalName = mission.Map
            });
            resource.ResourceDependencies.Add(new ResourceDependency()
            {
                NeedsInternalName = mission.Mod
            });
            resource.ResourceContentFiles.Clear();


            // generate torrent
            var tempFile = Path.Combine(Path.GetTempPath(), mission.SanitizedFileName);

            File.WriteAllBytes(tempFile, mission.Mutator.ToArray());
            var creator = new TorrentCreator();

            creator.Path = tempFile;
            var torrentStream = new MemoryStream();

            creator.Create(torrentStream);
            try
            {
                File.Delete(tempFile);
            }
            catch { }

            var md5 = Hash.HashBytes(mission.Mutator.ToArray()).ToString();

            resource.ResourceContentFiles.Add(new ResourceContentFile()
            {
                FileName  = mission.SanitizedFileName,
                Length    = mission.Mutator.Length,
                LinkCount = 1,
                Links     = string.Format(MissionFileUrl, mission.MissionID),
                Md5       = md5
            });


            var basePath = GlobalConst.SiteDiskPath + @"\resources\";

            File.WriteAllBytes(string.Format(@"{2}\{0}_{1}.torrent", resource.InternalName.EscapePath(), md5, basePath), torrentStream.ToArray());

            File.WriteAllBytes(string.Format(@"{1}\{0}.metadata.xml.gz", resource.InternalName.EscapePath(), basePath),
                               MetaDataCache.SerializeAndCompressMetaData(modInfo));

            File.WriteAllBytes(string.Format(GlobalConst.SiteDiskPath + @"\img\missions\{0}.png", mission.MissionID, basePath), mission.Image.ToArray());
        }