MainScene.gd 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. extends Control
  2. # Referencias a los nodos de la UI
  3. onready var company_option_button = $VBoxContainer/HBoxContainer_Selectors/CompanyOptionButton
  4. onready var synergy_option_button = $VBoxContainer/HBoxContainer_Selectors/SynergyOptionButton
  5. onready var search_button = $VBoxContainer/HBoxContainer_Selectors/SearchButton
  6. onready var item_list_results = $VBoxContainer/ItemList_Results
  7. onready var rich_text_label_details = $VBoxContainer/RichTextLabel_Details
  8. onready var download_button = $VBoxContainer/DownloadButton
  9. onready var file_dialog = $FileDialog
  10. # --- NODOS PARA EXPORTACIÓN MASIVA ---
  11. onready var export_all_button = $VBoxContainer/HBoxContainer_Bulk/ExportAllButton
  12. onready var progress_label = $VBoxContainer/HBoxContainer_Bulk/ProgressLabel
  13. onready var directory_dialog = $DirectoryDialog
  14. const SYNERGY_TYPES = [
  15. "Strategic Alliance",
  16. "Customer-Supplier",
  17. "Tech Integration",
  18. "Competitor Analysis"
  19. ]
  20. var _current_matches = []
  21. var _selected_match_data = null
  22. func _ready():
  23. # Conexiones de señales
  24. search_button.connect("pressed", self, "_on_search_button_pressed")
  25. item_list_results.connect("item_selected", self, "_on_result_item_selected")
  26. download_button.connect("pressed", self, "_on_download_button_pressed")
  27. file_dialog.connect("file_selected", self, "_on_file_dialog_file_selected")
  28. # --- NUEVAS CONEXIONES ---
  29. export_all_button.connect("pressed", self, "_on_export_all_button_pressed")
  30. directory_dialog.connect("dir_selected", self, "_on_directory_selected")
  31. populate_company_dropdown()
  32. populate_synergy_dropdown()
  33. item_list_results.clear()
  34. rich_text_label_details.bbcode_enabled = true
  35. rich_text_label_details.text = "Select a company and a synergy type, then press 'Search'."
  36. download_button.disabled = true
  37. progress_label.text = ""
  38. file_dialog.filters = PoolStringArray(["*.json ; JSON Files"])
  39. directory_dialog.mode = FileDialog.MODE_OPEN_DIR # Forzar modo de selección de directorio
  40. func populate_company_dropdown():
  41. var company_names = CompanyDB.get_all_company_names()
  42. for name in company_names:
  43. company_option_button.add_item(name)
  44. func populate_synergy_dropdown():
  45. for synergy_type in SYNERGY_TYPES:
  46. synergy_option_button.add_item(synergy_type)
  47. # --- LÓGICA DE LA INTERFAZ (BÚSQUEDA INDIVIDUAL) ---
  48. func _on_search_button_pressed():
  49. search_button.disabled = true
  50. download_button.disabled = true
  51. _selected_match_data = null
  52. item_list_results.clear()
  53. _current_matches.clear()
  54. rich_text_label_details.text = "Searching..."
  55. yield(get_tree(), "idle_frame")
  56. var selected_company_name = company_option_button.get_item_text(company_option_button.selected)
  57. var selected_synergy_type = synergy_option_button.get_item_text(synergy_option_button.selected)
  58. _find_and_display_matches(selected_company_name, selected_synergy_type)
  59. search_button.disabled = false
  60. func _on_result_item_selected(index):
  61. if index >= _current_matches.size():
  62. return
  63. _selected_match_data = _current_matches[index]
  64. var company_details = _selected_match_data["company"]
  65. var reason = _selected_match_data["reason"]
  66. rich_text_label_details.bbcode_text = ""
  67. rich_text_label_details.append_bbcode("[b]Name:[/b] " + company_details.get("company_name", "N/A") + "\n")
  68. rich_text_label_details.append_bbcode("[b]Website:[/b] " + company_details.get("website", "N/A") + "\n\n")
  69. var description = company_details.get("description", {}).get("brief", "No hay descripción breve.")
  70. rich_text_label_details.append_bbcode("[b]Description:[/b] " + description + "\n\n")
  71. rich_text_label_details.append_bbcode("[b]Synergy Analysis (" + _selected_match_data["synergy_type"] + "):[/b]\n")
  72. rich_text_label_details.append_bbcode(reason)
  73. func _on_download_button_pressed():
  74. if _current_matches.empty():
  75. return
  76. var source_company_name = company_option_button.get_item_text(company_option_button.selected).replace(" ", "_")
  77. var synergy_type = _current_matches[0]["synergy_type"].replace(" ", "_")
  78. file_dialog.current_file = "%s_%s_Matches.json" % [source_company_name, synergy_type]
  79. file_dialog.popup_centered()
  80. func _on_file_dialog_file_selected(path):
  81. if _current_matches.empty():
  82. return
  83. var matches_to_save = []
  84. for match_data in _current_matches:
  85. var single_match_dict = {
  86. "matched_company": match_data["company"].get("company_name"),
  87. "synergy_type": match_data["synergy_type"],
  88. "justification": match_data["reason"].replace("[b]", "").replace("[/b]", "").replace("[i]", "").replace("[/i]", "").replace("[ul]", "").replace("[/ul]", "").replace("[li]", "- ")
  89. }
  90. matches_to_save.append(single_match_dict)
  91. var json_string = JSON.print(matches_to_save, "\t")
  92. var file = File.new()
  93. if file.open(path, File.WRITE) == OK:
  94. file.store_string(json_string)
  95. file.close()
  96. else:
  97. print("Error saving JSON file.")
  98. # --- LÓGICA DE EXPORTACIÓN MASIVA ---
  99. func _on_export_all_button_pressed():
  100. directory_dialog.popup_centered()
  101. func _on_directory_selected(path):
  102. search_button.disabled = true
  103. export_all_button.disabled = true
  104. download_button.disabled = true
  105. var all_companies = CompanyDB.company_data
  106. var total_companies = all_companies.size()
  107. var matches_found = 0
  108. for i in range(total_companies):
  109. var source_company = all_companies[i]
  110. var source_company_name = source_company.get("company_name", "Unknown")
  111. progress_label.text = "Processing %d/%d: %s..." % [i + 1, total_companies, source_company_name]
  112. yield(get_tree(), "idle_frame")
  113. var company_matches = []
  114. for target_company in all_companies:
  115. if source_company_name == target_company.get("company_name", "Unknown2"):
  116. continue
  117. for synergy_type in SYNERGY_TYPES:
  118. var reason = _get_synergy_reason(source_company, target_company, synergy_type)
  119. if reason:
  120. matches_found += 1
  121. company_matches.append({
  122. "matched_company": target_company.get("company_name"),
  123. "synergy_type": synergy_type,
  124. "justification": reason.replace("[b]", "").replace("[/b]", "").replace("[i]", "").replace("[/i]", "").replace("[ul]", "").replace("[/ul]", "").replace("[li]", "- ")
  125. })
  126. # --- LÓGICA DE GUARDADO MODIFICADA ---
  127. var json_string_to_save = ""
  128. # Si se encontraron matches, se guarda la lista de matches.
  129. if not company_matches.empty():
  130. json_string_to_save = JSON.print(company_matches, "\t")
  131. # Si NO se encontraron, se guarda un mensaje de estado.
  132. else:
  133. var no_match_data = {
  134. "status": "No synergies found",
  135. "message": "No potential synergies were identified for %s based on the current criteria." % source_company_name
  136. }
  137. json_string_to_save = JSON.print(no_match_data, "\t")
  138. # Guardar el archivo en cualquier caso.
  139. var filename = "%s_Synergies.json" % source_company_name.replace(" ", "_")
  140. var file_path = path.plus_file(filename)
  141. var file = File.new()
  142. if file.open(file_path, File.WRITE) == OK:
  143. file.store_string(json_string_to_save)
  144. file.close()
  145. progress_label.text = "Export complete! Found %d potential synergies across %d companies." % [matches_found, total_companies]
  146. search_button.disabled = false
  147. export_all_button.disabled = false
  148. # --- LÓGICA DE BÚSQUEDA Y ANÁLISIS ---
  149. func _find_and_display_matches(company_name, synergy_type):
  150. var source_company = CompanyDB.get_company_by_name(company_name)
  151. if not source_company:
  152. rich_text_label_details.text = "Error: Could not find data for the base company."
  153. return
  154. _current_matches.clear()
  155. var all_companies = CompanyDB.company_data
  156. for target_company in all_companies:
  157. if target_company.get("company_name") == source_company.get("company_name"):
  158. continue
  159. var reason = _get_synergy_reason(source_company, target_company, synergy_type)
  160. if reason:
  161. _current_matches.append({
  162. "company": target_company,
  163. "reason": reason,
  164. "synergy_type": synergy_type
  165. })
  166. if not _current_matches.empty():
  167. for match_data in _current_matches:
  168. item_list_results.add_item(match_data["company"].get("company_name"))
  169. rich_text_label_details.text = "Found %d matches. Select one to see the analysis." % _current_matches.size()
  170. download_button.disabled = false
  171. else:
  172. rich_text_label_details.text = "No matches found for the selected criteria."
  173. download_button.disabled = true
  174. func _get_synergy_reason(comp_a, comp_b, synergy_type):
  175. match synergy_type:
  176. "Competitor Analysis":
  177. return _get_competitor_reason(comp_a, comp_b)
  178. "Strategic Alliance":
  179. return _get_strategic_alliance_reason(comp_a, comp_b)
  180. "Customer-Supplier":
  181. return _get_customer_supplier_reason(comp_a, comp_b)
  182. "Tech Integration":
  183. return _get_tech_integration_reason(comp_a, comp_b)
  184. return null
  185. func _get_competitor_reason(comp_a, comp_b):
  186. var sectors_a = comp_a.get("target_markets", {}).get("sectors", [])
  187. var sectors_b = comp_b.get("target_markets", {}).get("sectors", [])
  188. var services_a = comp_a.get("offerings", {}).get("services", [])
  189. var services_b = comp_b.get("offerings", {}).get("services", [])
  190. var shared_sectors = _get_array_intersection(sectors_a, sectors_b)
  191. if shared_sectors.empty(): return null
  192. var shared_services = _get_array_intersection(services_a, services_b)
  193. if shared_services.empty(): return null
  194. var reason = "A competitive overlap exists between [b]%s[/b] and [b]%s[/b].\n\n" % [comp_a.get("company_name"), comp_b.get("company_name")]
  195. reason += "Key points of analysis:\n"
  196. reason += "[ul][li]Both companies operate in the following shared sectors: [b]%s[/b].[/li]\n" % PoolStringArray(shared_sectors).join(", ")
  197. reason += "[li]They offer similar services to the market, including: [b]%s[/b].[/li][/ul]\n" % PoolStringArray(shared_services).join(", ")
  198. reason += "This alignment in market focus and service offerings suggests they are direct or indirect competitors."
  199. return reason
  200. func _get_strategic_alliance_reason(comp_a, comp_b):
  201. var sectors_a = comp_a.get("target_markets", {}).get("sectors", [])
  202. var sectors_b = comp_b.get("target_markets", {}).get("sectors", [])
  203. var keywords_a = comp_a.get("capability_map", {}).get("core_technical_keywords", [])
  204. var keywords_b = comp_b.get("capability_map", {}).get("core_technical_keywords", [])
  205. var shared_sectors = _get_array_intersection(sectors_a, sectors_b)
  206. if shared_sectors.empty(): return null
  207. var shared_keywords = _get_array_intersection(keywords_a, keywords_b)
  208. if shared_keywords.size() > 3: return null
  209. var reason = "A potential strategic alliance exists between [b]%s[/b] and [b]%s[/b].\n\n" % [comp_a.get("company_name"), comp_b.get("company_name")]
  210. reason += "Justification:\n"
  211. reason += "[ul][li]Both companies are active in the [b]%s[/b] sector(s).[/li]\n" % PoolStringArray(shared_sectors).join(", ")
  212. reason += "[li][b]%s[/b]'s expertise in [i]%s[/i] could be complemented by [b]%s[/b]'s capabilities in [i]%s[/i].[/li][/ul]\n" % [comp_a.get("company_name"), PoolStringArray(keywords_a).join(", "), comp_b.get("company_name"), PoolStringArray(keywords_b).join(", ")]
  213. reason += "A partnership could lead to a more comprehensive and integrated solution for their shared market."
  214. return reason
  215. func _get_customer_supplier_reason(comp_a, comp_b):
  216. var reason_a_is_customer = _check_customer_supplier_direction(comp_a, comp_b)
  217. if reason_a_is_customer: return reason_a_is_customer
  218. var reason_b_is_customer = _check_customer_supplier_direction(comp_b, comp_a)
  219. if reason_b_is_customer: return reason_b_is_customer
  220. return null
  221. func _check_customer_supplier_direction(customer, supplier):
  222. var customer_domains = customer.get("capability_map", {}).get("application_domains", [])
  223. var supplier_services = supplier.get("offerings", {}).get("services", [])
  224. var match_keywords = _get_array_intersection(customer_domains, supplier_services)
  225. if match_keywords.empty(): return null
  226. var reason = "A potential customer-supplier relationship exists between [b]%s[/b] (Customer) and [b]%s[/b] (Supplier).\n\n" % [customer.get("company_name"), supplier.get("company_name")]
  227. reason += "Justification:\n"
  228. reason += "[ul][li][b]%s[/b]'s focus on the [b]%s[/b] domain(s) aligns directly with the services offered by [b]%s[/b], such as [b]%s[/b].[/li][/ul]\n" % [customer.get("company_name"), PoolStringArray(customer_domains).join(", "), supplier.get("company_name"), PoolStringArray(supplier_services).join(", ")]
  229. reason += "[b]%s[/b] could enhance its offerings by integrating [b]%s[/b]'s specialized solutions." % [customer.get("company_name"), supplier.get("company_name")]
  230. return reason
  231. func _get_tech_integration_reason(comp_a, comp_b):
  232. var hardware_a = comp_a.get("technology_stack", {}).get("hardware", [])
  233. var software_a = comp_a.get("technology_stack", {}).get("software", [])
  234. var hardware_b = comp_b.get("technology_stack", {}).get("hardware", [])
  235. var software_b = comp_b.get("technology_stack", {}).get("software", [])
  236. var integration_path = null
  237. if not _get_array_intersection(hardware_a, software_b).empty() or not _get_array_intersection(software_a, hardware_b).empty():
  238. integration_path = "Hardware/Software"
  239. if not integration_path: return null
  240. var reason = "A technological integration opportunity exists between [b]%s[/b] and [b]%s[/b].\n\n" % [comp_a.get("company_name"), comp_b.get("company_name")]
  241. reason += "Justification:\n"
  242. reason += "[ul][li]There is a clear [b]%s[/b] integration path.[/li]\n" % integration_path
  243. reason += "[li][b]%s[/b]'s hardware expertise ([i]%s[/i]) and software capabilities ([i]%s[/i]) are complementary to [b]%s[/b]'s stack ([i]%s[/i] hardware, [i]%s[/i] software).[/li][/ul]\n" % [comp_a.get("company_name"), PoolStringArray(hardware_a).join(", "), PoolStringArray(software_a).join(", "), comp_b.get("company_name"), PoolStringArray(hardware_b).join(", "), PoolStringArray(software_b).join(", ")]
  244. reason += "Combining their technologies could result in a powerful, turnkey solution."
  245. return reason
  246. func _get_array_intersection(arr1, arr2):
  247. var intersection = []
  248. for item in arr1:
  249. if item in arr2:
  250. intersection.append(item)
  251. return intersection