text: /*
   * Copyright (c) Contributors to the Open 3D Engine Project. For complete copyright and license terms please see the LICENSE at the root of this distribution.
   * 
   * SPDX-License-Identifier: Apache-2.0 OR MIT
   *
   */
  
  #pragma once
  
  #if !defined(Q_MOC_RUN)
  #include <CrySystemBus.h>
  
  // AZ
  #include <AzCore/Component/EntityBus.h>
  #include <AzCore/Memory/SystemAllocator.h>
  #include <AzCore/PlatformDef.h>
  #include <AzCore/std/containers/unordered_map.h>
  #include <AzQtComponents/Components/StyledDockWidget.h>
  #include <AzToolsFramework/API/EntityCompositionNotificationBus.h>
  #include <AzToolsFramework/API/ToolsApplicationAPI.h>
  #include <AzToolsFramework/Entity/EditorEntityContextBus.h>
  #include <AzToolsFramework/Prefab/PrefabPublicNotificationBus.h>
  #include <AzToolsFramework/UI/PropertyEditor/EntityPropertyEditor.hxx>
  #include <AzToolsFramework/UI/PropertyEditor/PropertyEditorAPI.h>
  
  // GraphModel
  #include <GraphModel/Integration/EditorMainWindow.h>
  
  // LandscapeCanvas
  #include <LandscapeCanvas/LandscapeCanvasBus.h>
  #endif
  
  namespace LandscapeCanvasEditor
  {
      ////////////////////////////////////////////////////////////////////////
      // Temporary classes for using a custom Pinned Inspector as a Node Inspector
      // that will use the selected nodes in the graph to drive the Node Inspector
      // based on the corresponding Vegetation Entities. These will be removed
      // once a generic Node Inspector has been implemented for the base EditorMainWindow.
      class CustomEntityPropertyEditor
          : public AzToolsFramework::EntityPropertyEditor
      {
      public:
          AZ_CLASS_ALLOCATOR(CustomEntityPropertyEditor, AZ::SystemAllocator, 0);
  
          CustomEntityPropertyEditor(QWidget* parent = nullptr);
  
      protected:
          void CloseInspectorWindow() override;
          QString GetEntityDetailsLabelText() const override;
      };
  
      class CustomNodeInspectorDockWidget
          : public AzQtComponents::StyledDockWidget
      {
      public:
          AZ_CLASS_ALLOCATOR(CustomNodeInspectorDockWidget, AZ::SystemAllocator, 0);
  
          CustomNodeInspectorDockWidget(QWidget* parent = nullptr);
  
          CustomEntityPropertyEditor* GetEntityPropertyEditor();
  
      private:
          CustomEntityPropertyEditor* m_propertyEditor = nullptr;
      };
      ////////////////////////////////////////////////////////////////////////
  
      struct LandscapeCanvasConfig
          : GraphCanvas::AssetEditorWindowConfig
      {
          GraphCanvas::GraphCanvasTreeItem* CreateNodePaletteRoot() override;
      };
  
      class MainWindow
          : public GraphModelIntegration::EditorMainWindow
          , protected LandscapeCanvas::LandscapeCanvasRequestBus::Handler
          , private AZ::EntitySystemBus::Handler
          , private AzToolsFramework::EditorEntityContextNotificationBus::Handler
          , private AzToolsFramework::EditorPickModeNotificationBus::Handler
          , private AzToolsFramework::EntityCompositionNotificationBus::Handler
          , private AzToolsFramework::PropertyEditorEntityChangeNotificationBus::MultiHandler
          , private AzToolsFramework::ToolsApplicationNotificationBus::Handler
          , private AzToolsFramework::Prefab::PrefabPublicNotificationBus::Handler
          , private CrySystemEventBus::Handler
      {
          Q_OBJECT
  
      public:
          explicit MainWindow(QWidget* parent = nullptr);
          ~MainWindow() override;
  
      private:
          GraphModel::IGraphContextPtr GetGraphContext() const override;
  
          ////////////////////////////////////////////////////////////////////////
          // GraphModelIntegration::GraphControllerNotificationBus::Handler overrides
          void OnGraphModelNodeAdded(GraphModel::NodePtr node) override;
          void OnGraphModelNodeRemoved(GraphModel::NodePtr node) override;
          void PreOnGraphModelNodeRemoved(GraphModel::NodePtr node) override;
          void OnGraphModelConnectionAdded(GraphModel::ConnectionPtr connection) override;
          void OnGraphModelConnectionRemoved(GraphModel::ConnectionPtr connection) override;
          void OnGraphModelNodeWrapped(GraphModel::NodePtr wrapperNode, GraphModel::NodePtr node) override;
          void OnGraphModelGraphModified(GraphModel::NodePtr node) override;
          ////////////////////////////////////////////////////////////////////////
  
          ////////////////////////////////////////////////////////////////////////
          // GraphModelIntegration::EditorMainWindow overrides ...
          void OnEditorOpened(GraphCanvas::EditorDockWidget* dockWidget) override;
          void OnEditorClosing(GraphCanvas::EditorDockWidget* dockWidget) override;
          QAction* AddFileNewAction(QMenu* menu) override;
          QAction* AddFileOpenAction(QMenu* menu) override;
          QAction* AddFileSaveAction(QMenu* menu) override;
          QAction* AddFileSaveAsAction(QMenu* menu) override;
          QMenu* AddEditMenu() override;
          void HandleWrapperNodeActionWidgetClicked(GraphModel::NodePtr wrapperNode, const QRect& actionWidgetBoundingRect, const QPointF& scenePoint, const QPoint& screenPoint) override;
          GraphCanvas::Endpoint CreateNodeForProposal(const AZ::EntityId& connectionId, const GraphCanvas::Endpoint& endpoint, const QPointF& scenePoint, const QPoint& screenPoint) override;
          void OnSelectionChanged() override;
          void OnEntitiesSerialized(GraphCanvas::GraphSerialization& serializationTarget) override;
          void OnEntitiesDeserialized(const GraphCanvas::GraphSerialization&) override;
          ////////////////////////////////////////////////////////////////////////
  
          ////////////////////////////////////////////////////////////////////////
          // AZ::EntitySystemBus
          void OnEntityActivated(const AZ::EntityId& entityId) override;
          void OnEntityNameChanged(const AZ::EntityId& entityId, const AZStd::string& name) override;
          ////////////////////////////////////////////////////////////////////////
  
          bool HandleGraphOpened(const AZ::EntityId& rootEntityId, const GraphCanvas::DockWidgetId& dockWidgetId);
  
          ////////////////////////////////////////////////////////////////////////
          // AssetEditorRequestBus::Handler overrides
          GraphCanvas::ContextMenuAction::SceneReaction ShowNodeContextMenu(const AZ::EntityId& nodeId, const QPoint& screenPoint, const QPointF& scenePoint) override;
          ////////////////////////////////////////////////////////////////////////
  
          ////////////////////////////////////////////////////////////////////////
          // LandscapeCanvas::LandscapeCanvasRequestBus::Handler overrides
          GraphCanvas::GraphId OnGraphEntity(const AZ::EntityId& entityId) override;
          GraphModel::NodePtr GetNodeMatchingEntityInGraph(const GraphCanvas::GraphId& graphId, const AZ::EntityId& entityId) override;
          GraphModel::NodePtr GetNodeMatchingEntityComponentInGraph(const GraphCanvas::GraphId& graphId, const AZ::EntityComponentIdPair& entityComponentId) override;
          GraphModel::NodePtrList GetAllNodesMatchingEntity(const AZ::EntityId& entityId) override;
          GraphModel::NodePtrList GetAllNodesMatchingEntityComponent(const AZ::EntityComponentIdPair& entityComponentId) override;
          ////////////////////////////////////////////////////////////////////////
  
          ////////////////////////////////////////////////////////////////////////
          // GraphCanvas::AssetEditorMainWindow overrides
          bool ConfigureDefaultLayout() override;
          ////////////////////////////////////////////////////////////////////////
  
          ////////////////////////////////////////////////////////////////////////
          // AzToolsFramework::EditorEntityContextNotificationBus overrides
          void OnEditorEntityCreated(const AZ::EntityId& entityId) override;
          void OnEditorEntityDeleted(const AZ::EntityId& entityId) override;
          ////////////////////////////////////////////////////////////////////////
  
          void HandleEditorEntityCreated(const AZ::EntityId& entityId, GraphCanvas::GraphId graphId = GraphCanvas::GraphId());
          void QueuedEditorEntityDeleted(const AZ::EntityId& entityId);
          void HandleEditorEntityDeleted(const AZ::EntityId& entityId);
  
          ////////////////////////////////////////////////////////////////////////
          // AzToolsFramework::EditorPickModeNotificationBus overrides
          void OnEntityPickModeStarted() override;
          void OnEntityPickModeStopped() override;
          ////////////////////////////////////////////////////////////////////////
  
          ////////////////////////////////////////////////////////////////////////
          // AzToolsFramework::EntityCompositionNotificationBus overrides
          void OnEntityComponentAdded(const AZ::EntityId& entityId, const AZ::ComponentId& componentId) override;
          void OnEntityComponentRemoved(const AZ::EntityId& entityId, const AZ::ComponentId& componentId) override;
          void OnEntityComponentEnabled(const AZ::EntityId& entityId, const AZ::ComponentId& componentId) override;
          void OnEntityComponentDisabled(const AZ::EntityId& entityId, const AZ::ComponentId& componentId) override;
          ////////////////////////////////////////////////////////////////////////
  
          ////////////////////////////////////////////////////////////////////////
          // AzToolsFramework::PropertyEditorEntityChangeNotificationBus overrides
          void OnEntityComponentPropertyChanged(AZ::ComponentId changedComponentId) override;
          ////////////////////////////////////////////////////////////////////////
  
          ////////////////////////////////////////////////////////////////////////
          // AzToolsFramework::ToolsApplicationNotificationBus overrides
          void EntityParentChanged(AZ::EntityId entityId, AZ::EntityId newParentId, AZ::EntityId oldParentId) override;
          ////////////////////////////////////////////////////////////////////////
  
          //! PrefabPublicNotificationBus overrides
          void OnPrefabInstancePropagationBegin() override;
          void OnPrefabInstancePropagationEnd() override;
  
          ////////////////////////////////////////////////////////////////////////
          // CrySystemEventBus overrides
          void OnCryEditorEndCreate() override;
          void OnCryEditorEndLoad() override;
          void OnCryEditorCloseScene() override;
          void OnCryEditorSceneClosed() override;
          ////////////////////////////////////////////////////////////////////////
  
          ////////////////////////////////////////////////////////////////////////
          // GraphCanvas::AssetEditorNotificationBus overrides
          void PostOnActiveGraphChanged() override;
          ////////////////////////////////////////////////////////////////////////
  
          void GetChildrenTree(const AZ::EntityId& rootEntityId, AzToolsFramework::EntityIdList& childrenList);
  
          QString GetPropertyPathForSlot(GraphModel::SlotPtr slot, GraphModel::DataType::Enum dataType, int elementIndex = 0);
          void UpdateConnectionData(GraphModel::ConnectionPtr connection, bool added);
  
          AZ::u32 GetWrappedNodeLayoutOrder(GraphModel::NodePtr node);
  
          AZ::EntityId GetRootEntityIdForGraphId(const GraphCanvas::GraphId& graphId);
  
          AZ::ComponentId AddComponentTypeIdToEntity(const AZ::EntityId& entityId, AZ::TypeId componentToAddTypeId);
          void AddComponentForNode(GraphModel::NodePtr node, const AZ::EntityId& entityId);
          void HandleNodeCreated(GraphModel::NodePtr node);
          void HandleNodeAdded(GraphModel::NodePtr node);
  
          using EntityIdNodeMap = AZStd::unordered_map<AZ::EntityId, GraphModel::NodePtr>;
          using EntityIdNodeMaps = AZStd::vector<EntityIdNodeMap>;
          enum EntityIdNodeMapEnum
          {
              Invalid = -1,
              Shapes = 0,
              Gradients,
              VegetationAreas,
              Count
          };
  
          using EntityComponentCallback = AZStd::function<void(const AZ::EntityId& entityId, AZ::Component* component, bool isDisabled)>;
          using NodeSlotPair = AZStd::pair<GraphModel::NodePtr, GraphModel::SlotPtr>;
          using ConnectionsList = AZStd::vector<AZStd::pair<NodeSlotPair, NodeSlotPair>>;
          void UpdateEntityIdNodeMap(GraphCanvas::GraphId, GraphModel::NodePtr node);
          EntityIdNodeMap* GetEntityIdNodeMap(GraphCanvas::GraphId, GraphModel::NodePtr node);
          void ParseNodeConnections(GraphCanvas::GraphId graphId, GraphModel::NodePtr node, ConnectionsList& connections);
          void UpdateConnections(GraphModel::NodePtr node);
          GraphCanvas::GraphId FindGraphContainingEntity(const AZ::EntityId& entityId);
          void EnumerateEntityComponentTree(const AZ::EntityId& rootEntityId, EntityComponentCallback callback);
          void InitialEntityGraph(const AZ::EntityId& entityId, GraphCanvas::GraphId graphId);
          GraphModel::NodePtrList RefreshEntityComponentNodes(const AZ::EntityId& targetEntityId, GraphCanvas::GraphId graphId);
          void PlaceNewNode(GraphCanvas::GraphId graphId, LandscapeCanvas::BaseNode::BaseNodePtr node);
          int GetInboundDataSlotIndex(GraphModel::NodePtr node, GraphModel::DataTypePtr dataType, GraphModel::SlotPtr targetSlot);
  
          //! Determines whether or not we should allow the user to interact with the graph
          //! This should be disabled when there is no level currently loaded
          void UpdateGraphEnabled();
  
          //! Return the input data slot on the node that matches the specified data type for the specified index.
          //!   - If this is a normal slot, it will just return the appropriate slot that is found.
          //!   - If this is an extendable slot, then slot(s) may need to be added in order to satisfy the requested index.
          GraphModel::SlotPtr EnsureInboundDataSlotWithIndex(GraphCanvas::GraphId graphId, GraphModel::NodePtr node, GraphModel::DataTypePtr dataType, int index);
  
          AZ::SerializeContext* m_serializeContext = nullptr;
  
          bool m_ignoreGraphUpdates = false;
          bool m_prefabPropagationInProgress = false;
          bool m_inObjectPickMode = false;
  
          using DeletedNodePositionsMap = AZStd::unordered_map<AZ::EntityComponentIdPair, AZ::Vector2>;
          AZStd::unordered_map<GraphCanvas::GraphId, DeletedNodePositionsMap> m_deletedNodePositions;
          AzToolsFramework::EntityIdList m_queuedEntityDeletes;
  
          AZStd::unordered_map<AZ::Uuid, AZ::u32> m_wrappedNodeLayoutOrderMap;
  
          /// Keep track of the dock widget for the graph that represents the Vegetation Entity
          AZStd::unordered_map<AZ::EntityId, GraphCanvas::DockWidgetId> m_dockWidgetsByEntity;
  
          /// Keep track of the EntityId/Node mappings per graph for performance reasons so that we
          /// don't have to parse through all the nodes in a graph to find right one when connecting
          /// slots based on the EntityId fields in the component properties.  The mappings are tracked
          /// by type as well for faster lookup since the slot data types are separated (shape, gradient, area).
          AZStd::unordered_map<GraphCanvas::GraphId, EntityIdNodeMaps> m_entityIdNodeMapsByGraph;
  
          CustomNodeInspectorDockWidget* m_customNodeInspector = nullptr;
  
          QAction* m_fileNewAction = nullptr;
      };
  } 
  