diff --git a/gui/fitDiffFrame.py b/gui/fitDiffFrame.py index 1b2ae4aec..4930e1dd0 100644 --- a/gui/fitDiffFrame.py +++ b/gui/fitDiffFrame.py @@ -20,15 +20,19 @@ # noinspection PyPackageRequirements import wx -from collections import Counter +import re -from eos.const import FittingSlot from service.fit import Fit as svcFit -from service.port.eft import exportEft, importEft, _importPrepare +from service.port.eft import exportEft from service.const import PortEftOptions _t = wx.GetTranslation +# Regex for parsing items: itemName x? quantity?, ,? chargeName? +ITEM_REGEX = re.compile( + r"^(?P[-\'\w\s]+?)x?\s*(?P\d+)?\s*(?:,\s*(?P[-\'\w\s]+))?$" +) + class FitDiffFrame(wx.Frame): """A frame to display differences between two fits.""" @@ -169,158 +173,44 @@ class FitDiffFrame(wx.Frame): self.diffText.SetValue('\n'.join(diffLines)) def parsePastedFit(self, text): - """Parse pasted EFT text into a fit object.""" - try: - lines = _importPrepare(text.splitlines()) - if not lines: - return None - return importEft(lines) - except Exception: - return None + """Parse pasted EFT text into a map of item name to count.""" + items = {} + for line in text.splitlines(): + line = line.strip() + if not line or line.startswith("["): + continue + match = ITEM_REGEX.match(line) + if match: + item_name = match.group("itemName").strip() + quantity = match.group("quantity") + count = int(quantity) if quantity else 1 + if item_name not in items: + items[item_name] = 0 + items[item_name] += count + return items - def calculateDiff(self, fit1, fit2): + def calculateDiff(self, fit1_items, fit2_items): """Calculate items needed to transform fit1 into fit2. - Returns a list of strings in the format: " " - Only shows items that need to be added (no negative values). + Returns a list of strings showing additions and extra items. """ diffLines = [] - # Get module counts by type for each fit (grouped by slot type) - fit1_modules = self.getModuleCounts(fit1) - fit2_modules = self.getModuleCounts(fit2) + all_items = set(fit1_items.keys()) | set(fit2_items.keys()) + additions = [] + extras = [] - # Slot order - slotOrder = [ - FittingSlot.HIGH, - FittingSlot.MED, - FittingSlot.LOW, - FittingSlot.RIG, - FittingSlot.SUBSYSTEM, - FittingSlot.SERVICE, - ] - - # Diff modules by slot - only show items needed to add - for slot in slotOrder: - fit1_slot_modules = fit1_modules.get(slot, Counter()) - fit2_slot_modules = fit2_modules.get(slot, Counter()) - - all_module_types = set(fit1_slot_modules.keys()) | set(fit2_slot_modules.keys()) - slot_diff_lines = [] - for module_type in sorted(all_module_types): - count1 = fit1_slot_modules.get(module_type, 0) - count2 = fit2_slot_modules.get(module_type, 0) - if count2 > count1: - slot_diff_lines.append(f"{module_type} x{count2 - count1}") - - if slot_diff_lines: - if diffLines: - diffLines.append("") - diffLines.extend(slot_diff_lines) - - # Get drone counts - fit1_drones = self.getDroneCounts(fit1) - fit2_drones = self.getDroneCounts(fit2) - - all_drone_types = set(fit1_drones.keys()) | set(fit2_drones.keys()) - for drone_type in sorted(all_drone_types): - count1 = fit1_drones.get(drone_type, 0) - count2 = fit2_drones.get(drone_type, 0) + for item in sorted(all_items): + count1 = fit1_items.get(item, 0) + count2 = fit2_items.get(item, 0) if count2 > count1: - diffLines.append(f"{drone_type} x{count2 - count1}") + additions.append(f"{item} x{count2 - count1}") + elif count1 > count2: + extras.append(f"{item} x-{count1 - count2}") - # Get fighter counts - fit1_fighters = self.getFighterCounts(fit1) - fit2_fighters = self.getFighterCounts(fit2) - - all_fighter_types = set(fit1_fighters.keys()) | set(fit2_fighters.keys()) - for fighter_type in sorted(all_fighter_types): - count1 = fit1_fighters.get(fighter_type, 0) - count2 = fit2_fighters.get(fighter_type, 0) - if count2 > count1: - diffLines.append(f"{fighter_type} x{count2 - count1}") - - # Get cargo counts - fit1_cargo = self.getCargoCounts(fit1) - fit2_cargo = self.getCargoCounts(fit2) - - all_cargo_types = set(fit1_cargo.keys()) | set(fit2_cargo.keys()) - for cargo_type in sorted(all_cargo_types): - count1 = fit1_cargo.get(cargo_type, 0) - count2 = fit2_cargo.get(cargo_type, 0) - if count2 > count1: - diffLines.append(f"{cargo_type} x{count2 - count1}") - - # Get implants - fit1_implants = self.getImplantNames(fit1) - fit2_implants = self.getImplantNames(fit2) - - for implant in sorted(fit2_implants - fit1_implants): - diffLines.append(f"{implant} x1") - - # Get boosters - fit1_boosters = self.getBoosterNames(fit1) - fit2_boosters = self.getBoosterNames(fit2) - - for booster in sorted(fit2_boosters - fit1_boosters): - diffLines.append(f"{booster} x1") + diffLines.extend(additions) + if additions and extras: + diffLines.extend(["", ""]) + diffLines.extend(extras) return diffLines - - def getModuleCounts(self, fit): - """Get a counter of module types for a fit, grouped by slot type. - - Returns a dict mapping FittingSlot -> Counter of module names. - Position doesn't matter, just counts by module name. - """ - counts_by_slot = {} - for module in fit.modules: - if module.isEmpty: - continue - slot = module.slot - if slot not in counts_by_slot: - counts_by_slot[slot] = Counter() - # Use item type name for comparison - name = module.item.typeName if module.item else "" - counts_by_slot[slot][name] += 1 - return counts_by_slot - - def getDroneCounts(self, fit): - """Get a counter of drone types for a fit.""" - counts = Counter() - for drone in fit.drones: - if drone.item: - counts[drone.item.typeName] += drone.amount - return counts - - def getFighterCounts(self, fit): - """Get a counter of fighter types for a fit.""" - counts = Counter() - for fighter in fit.fighters: - if fighter.item: - counts[fighter.item.typeName] += fighter.amount - return counts - - def getCargoCounts(self, fit): - """Get a counter of cargo items for a fit.""" - counts = Counter() - for cargo in fit.cargo: - if cargo.item: - counts[cargo.item.typeName] += cargo.amount - return counts - - def getImplantNames(self, fit): - """Get a set of implant names for a fit.""" - names = set() - for implant in fit.implants: - if implant.item: - names.add(implant.item.typeName) - return names - - def getBoosterNames(self, fit): - """Get a set of booster names for a fit.""" - names = set() - for booster in fit.boosters: - if booster.item: - names.add(booster.item.typeName) - return names