/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "stdafx.h"

//QT
#include <QSettings>

//Editor

#include <EditorDefs.h>
#include <BaseLibraryManager.h>
#include <IEditor.h>
#include <IEditorParticleUtils.h>
#include <Util/Variable.h>
#include <Particles/ParticleUIDefinition.h>
#include <Particles/ParticleItem.h>
#include <BaseLibraryItem.h>
#include <Include/IEditorParticleManager.h>

//EditorUI_QT
#include <../EditorUI_QT/DockWidgetTitleBar.h>
#include <../EditorUI_QT/AttributeView.h>
#include <../EditorUI_QT/FluidTabBar.h>
#include <../EditorUI_QT/ContextMenu.h>
#include <../EditorUI_QT/Utils.h>
#include <EditorUI_QTDLLBus.h>

// AZ
#include <AzFramework/API/ApplicationAPI.h>

//Local
#include "QT/DockableAttributePanel.h"


DockableAttributePanel::DockableAttributePanel(QWidget* parent)
    : FloatableDockPanel("", parent, Qt::WindowFlags(), false)
    , m_titleBar(nullptr)
    , m_attributeView(nullptr)
    , m_openParticleTabBar(nullptr)
    , m_pParticleUI(nullptr)
    , m_titleBarMenu(nullptr)
    , m_TabBarDynamicTabIndex(-1)
    , m_IgnoreAttributeRefresh(false)
{
    m_vars.reset();

    //delete previous saved panel layout since it doesn't include customized attribute configration 
    QSettings settings("Amazon", "Lumberyard");
    if (settings.value(PARTICLE_EDITOR_LAYOUT_SETTINGS_ATTRIBUTES_OLD).isNull() == false)
    {
        settings.remove(PARTICLE_EDITOR_LAYOUT_SETTINGS_ATTRIBUTES_OLD);
        settings.sync();
    }
}

DockableAttributePanel::~DockableAttributePanel()
{
    m_vars.reset();
    SAFE_DELETE(m_titleBar);
    SAFE_DELETE(m_openParticleTabBar);
    SAFE_DELETE(m_pParticleUI);
    SAFE_DELETE(m_titleBarMenu);
    SAFE_DELETE(m_attributeView);
}

void DockableAttributePanel::Init(const QString& panelName, CBaseLibraryManager* libraryManager)
{
    //Setup titlebar
    m_titleBar = new DockWidgetTitleBar(this);
    m_titleBar->SetupLabel(panelName);
    m_titleBar->SetShowMenuContextMenuCallback([&] {return GetTitleBarMenu();
        });
    setTitleBarWidget(m_titleBar);
    m_titleBarMenu = new QMenu;

    m_attributeView = new CAttributeView(this);
    m_attributeView->setObjectName("dwAttributeViewWidget");
    m_attributeView->setTitleBarWidget(CreateTabBar());
    m_attributeView->setFeatures(QDockWidget::NoDockWidgetFeatures);
    m_attributeView->setRefreshCallback([this](){ RefreshCurrentTab(); });

    //Setup Dock window
    setObjectName("dwAttributeView");
    setAllowedAreas(Qt::AllDockWidgetAreas);
    setWidget(m_attributeView);

    m_pParticleUI = new CParticleUIDefinition();
    m_vars = m_pParticleUI->CreateVars();

    m_attributeView->CreateDefaultConfigFile(m_vars);

    AZStd::string defaultAttributeViewLayoutPath(DEFAULT_ATTRIBUTE_VIEW_LAYOUT_PATH);
    AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::ResolveEnginePath, defaultAttributeViewLayoutPath);

    CAttributeViewConfig* attributeViewConfig = m_attributeView->CreateConfigFromFile(QString(defaultAttributeViewLayoutPath.c_str()));


    CRY_ASSERT(attributeViewConfig);
    m_attributeView->SetConfiguration(*attributeViewConfig, m_vars);
    SetOnVariableChangeCallbackRecurse(m_vars.get());

    //display helper text
    setWindowTitle("Attributes");
    m_attributeView->ShowDefaultView();
    connect(m_attributeView, &CAttributeView::SignalRefreshAttributeView, this, &DockableAttributePanel::RefreshGroupNodeSettings);
    connect(m_attributeView, &CAttributeView::SignalBuildCustomAttributeList, this, &DockableAttributePanel::PassThroughSignalBuildPanelList);
    connect(m_attributeView, &CAttributeView::SignalAddAttributePreset, this, &DockableAttributePanel::PassThroughSignalAddPreset);
    connect(m_attributeView, &CAttributeView::SignalResetPresetList, this, [=](){emit SignalResetPresetList(); });
    connect(m_attributeView, &CAttributeView::SignalRefreshAttributes, this, &DockableAttributePanel::RefreshCurrentParameterUI);
    connect(m_attributeView, &CAttributeView::SignalGetCurrentTabName, this, [=](QString& name){ name = GetCurrentTabText(); });
    connect(m_attributeView, &CAttributeView::SignalVarialbeUpdateHighlight, this, [=](bool ishighlight)
        {
            emit SignalLODParticleHighLight(ishighlight, m_currentLod, m_openParticleTabBar->tabText(m_openParticleTabBar->currentIndex()));
        });
    connect(m_attributeView, &CAttributeView::SignalIgnoreAttributeRefresh, this, [=](bool ignored) { m_IgnoreAttributeRefresh = ignored; });

    connect(m_attributeView, &CAttributeView::SignalItemUndoPoint, this, &DockableAttributePanel::OnItemUndoPoint);


    m_libraryManager = libraryManager;

    //pre-build attribute view's contents
    m_attributeView->FillFromConfiguration();
    //save default panel before load saved layout so it can be used for reset
    m_attributeView->getPanelWidget()->finalizePanels();
}

void DockableAttributePanel::LoadAttributeLayout(QByteArray data)
{
    CRY_ASSERT(m_attributeView);
    m_attributeView->LoadAttributeConfig(data);
}

void DockableAttributePanel::SaveAttributeLayout(QByteArray& out)
{
    CRY_ASSERT(m_attributeView);
    m_attributeView->SaveAttributeConfig(out);
}

void DockableAttributePanel::LoadSessionState()
{
    //load previous saved layout
    QSettings settings("Amazon", "Lumberyard");
    if (settings.value(PARTICLE_EDITOR_LAYOUT_SETTINGS_ATTRIBUTES).isNull() == false && m_attributeView)
    {
        LoadAttributeLayout(settings.value(PARTICLE_EDITOR_LAYOUT_SETTINGS_ATTRIBUTES).toByteArray());
    }
}

void DockableAttributePanel::SaveSessionState()
{
    CRY_ASSERT(m_attributeView);

    QByteArray saveData;
    SaveAttributeLayout(saveData);

    QSettings settings("Amazon", "Lumberyard");
    settings.setValue(PARTICLE_EDITOR_LAYOUT_SETTINGS_ATTRIBUTES, saveData);
    settings.sync();
}

void DockableAttributePanel::ResetToDefaultLayout()
{
    CRY_ASSERT(m_attributeView);

    //delete saved layout
    QSettings settings("Amazon", "Lumberyard");
    settings.remove(PARTICLE_EDITOR_LAYOUT_SETTINGS_ATTRIBUTES);
    settings.sync();

    //reset
    m_attributeView->ResetToDefaultLayout();
}

QShortcut* DockableAttributePanel::GetShortcut(ParamShortcuts item)
{
    CRY_ASSERT(GetIEditor());
    CRY_ASSERT(GetIEditor()->GetParticleUtils());
    CRY_ASSERT(m_attributeView);
    QShortcut* shortcut = nullptr;
    switch (item)
    {
    case DockableAttributePanel::ParamShortcuts::InsertComment:
    {
        shortcut = new QShortcut(GetIEditor()->GetParticleUtils()->HotKey_GetShortcut("Edit Menu.Insert Comment"), this);
        connect(shortcut, &QShortcut::activated, this, &DockableAttributePanel::OnInsertCommentTriggered);
    }
    break;
    default:
        break;
    }

    return shortcut;
}

QAction* DockableAttributePanel::GetMenuAction(TabActions action, const QString& contextItemName, QString displayAlias, QWidget* owner /* = nullptr*/)
{
    CRY_ASSERT(m_openParticleTabBar);

    QAction* act = nullptr;
    if (owner)
    {
        act = new QAction(displayAlias, owner);
    }
    else
    {
        act = new QAction(displayAlias, this);
    }
    switch (action)
    {
    case DockableAttributePanel::TabActions::CLOSE:
    {
        connect(act, &QAction::triggered, this, [=]()
            {
                m_openParticleTabBar->CloseTab(contextItemName);
            });
    }
    break;
    case DockableAttributePanel::TabActions::CLOSE_ALL:
    {
        connect(act, &QAction::triggered, this, [=]()
            {
                m_IgnoreAttributeRefresh = true;     //Ignore normal behavior as the refresh is not needed as we close each tab.
                m_openParticleTabBar->CloseAll();
                m_IgnoreAttributeRefresh = false;     //Allow refresh again.
            });
    }
    break;
    case DockableAttributePanel::TabActions::CLOSE_ALL_BUT_THIS:
    {
        connect(act, &QAction::triggered, this, [=]()
            {
                QString cntxtItemName = contextItemName.toUtf8();
                int tabIndex = FindItemInTabs(cntxtItemName);
                CRY_ASSERT(tabIndex != -1);
                m_IgnoreAttributeRefresh = true;     //Ignore normal behavior as the refresh is not needed as we close each tab.
                m_openParticleTabBar->CloseAllBut(tabIndex);
                m_IgnoreAttributeRefresh = false;     //Allow refresh again.
                tabIndex = FindItemInTabs(cntxtItemName);
                CRY_ASSERT(tabIndex != -1);
                SelectTab(tabIndex);     //This is being done to refresh the data and focus on the desired tab since it will be the only one remaining once this completes
            });
    }
    break;
    default:
    {
        act->setParent(nullptr);
        SAFE_DELETE(act);
        act = nullptr;
        break;
    }
    }
    return act;
}

void DockableAttributePanel::AddLayoutMenuItemsTo(QMenu* menu) //Pass through to the CAttributeView would be better setup with GetMenuAction like requests.
{
    CRY_ASSERT(m_attributeView);
    m_attributeView->AddLayoutMenu(menu);
}

void DockableAttributePanel::OpenInTab(CBaseLibraryItem* item)
{
    CRY_ASSERT(item);
    if (!item->IsParticleItem) // Return if the item is a folder
    {
        return;
    }
    QString particleLongName = item->GetFullName();

    int tabIndex = FindItemInTabs(particleLongName);
    if (tabIndex != -1) //Item is already in a tab
    {
        //If the tabIndex is the "dynamic" tab then we need to make it a "static" tab by resetting the dynamic tab index
        if (tabIndex == m_TabBarDynamicTabIndex)
        {
            m_TabBarDynamicTabIndex = -1;
        }
    }
    else //Item is not in a tab yet so add it as a "static" tab
    {
        QString library = item->GetLibrary()->GetName();
        QString tabTitle = item->GetFullName();

        ParticleTabData data;
        data.m_libraryItemName = particleLongName;
        data.m_libraryName = library;

        tabIndex = m_openParticleTabBar->addTab(tabTitle);
        data.m_isNewTab = true;//Mark the tab to be newly created, otherwise the m_openParticleTabBar::currentChanged event will cause an extra reload
        QVariant d;
        d.setValue(data);
        m_openParticleTabBar->setTabData(tabIndex, d);
        m_openParticleTabBar->setTabTextColor(tabIndex, GetTabTextColorFor(static_cast<CParticleItem*>(item)));
        if (m_openParticleTabBar->count() == 1)
        {
            ItemSelectionChanged(item);
            emit SignalTabSelectionChanged(QString(item->GetLibrary()->GetName()), QString(item->GetName()), true);
        }
    }
}

bool DockableAttributePanel::GetEnabledParameterValue(CParticleItem* item) const
{
    CRY_ASSERT(item);
    IParticleEffect* effect = item->GetEffect();
    if (effect)
    {
        return effect->IsEnabled();
    }
    return false;
}

void DockableAttributePanel::ToggleEnabledParameter(CParticleItem* item)
{
    CRY_ASSERT(item);
    SetEnabledParameter(item, !GetEnabledParameterValue(item));
}

void DockableAttributePanel::SetEnabledParameter(CParticleItem* item, bool enable)
{
    CRY_ASSERT(item);
    bool previousState = !enable;
    IParticleEffect* effect = item->GetEffect();
    if (effect)
    {
        previousState = effect->IsEnabled();
        effect->SetEnabled(enable);
        // This enable function is not updated through Cry reflection
        // Need to update particle params cached in UI if the particle being toggled is currently being selected.
        if (m_pParticleUI && m_pParticleUI->m_localParticleEffect == effect)
        {
            m_pParticleUI->m_localParams.bEnabled = enable;
        }
    }
    if (previousState == enable)
    {
        return;
    }
    RefreshOpenTabColors();
}

void DockableAttributePanel::UpdateColors(const QMap<QString, QColor>& colorMap)
{
    m_enabledTabTextColor = Qt::red;
    m_disabledTabTextColor = Qt::red;

    if (colorMap.contains("CDockWidgetTitleBarColor"))
    {
        m_enabledTabTextColor = colorMap["CDockWidgetTitleBarColor"];
    }

    if (colorMap.contains("CTextEditDisabledText"))
    {
        m_disabledTabTextColor = colorMap["CTextEditDisabledText"];
    }
    RefreshOpenTabColors();
}

void DockableAttributePanel::ItemSelectionChanged(CBaseLibraryItem* item)
{
    EditorUIPlugin::ScopedSuspendUndoPtr suspendUndo;
    EBUS_EVENT_RESULT(suspendUndo, EditorLibraryUndoRequestsBus, AddScopedSuspendUndo);

    m_currentLod = nullptr;
    CRY_ASSERT(m_attributeView);

    if (item && item->IsParticleItem)
    {
        m_attributeView->OnStartReload();
        m_IgnoreAttributeRefresh = true; //ignore updates
        {
            QString particleLongName = item->GetFullName();
            int tabIndex = FindItemInTabs(particleLongName);
            if (tabIndex != -1) //Item is already in a tab so select that tab
            {
                SelectTab(tabIndex);
            }
            else //Item is not in a tab yet so add it to the "dynamic" tab
            {
                QString library = item->GetLibrary()->GetName();
                QString tabTitle = item->GetFullName();

                ParticleTabData data;
                data.m_libraryItemName = particleLongName;
                data.m_libraryName = library;

                AddToDynamicTab(tabTitle, data);
            }
        }
        m_IgnoreAttributeRefresh = false; //respect updates

        RefreshParameterUI(static_cast<CParticleItem*>(item));
        m_attributeView->OnEndReload();
    }
    else
    {
        //Clear selection.
        m_attributeView->setEnabled(false);
    }
}

void DockableAttributePanel::LodItemSelectionChanged(CBaseLibraryItem* item, SLodInfo* lod)
{
    CRY_ASSERT(m_attributeView);

    this->m_currentLod = lod;

    if (item && item->IsParticleItem)
    {
        m_attributeView->OnStartReload();
        m_IgnoreAttributeRefresh = true; //ignore updates
        {
            QString particleLongName = item->GetFullName();
            int tabIndex = FindItemInTabs(particleLongName);
            if (tabIndex != -1) //Item is already in a tab so select that tab
            {
                SelectTab(tabIndex);
            }
            else //Item is not in a tab yet so add it to the "dynamic" tab
            {
                QString library = item->GetLibrary()->GetName();
                QString tabTitle = item->GetFullName();

                ParticleTabData data;
                data.m_libraryItemName = particleLongName;
                data.m_libraryName = library;

                AddToDynamicTab(tabTitle, data);
            }
        }
        m_IgnoreAttributeRefresh = false; //respect updates

        CParticleItem* particleItem = static_cast<CParticleItem*>(item);
        RefreshParameterUI(particleItem, lod);
        m_attributeView->OnEndReload();
    }
    else
    {
        //Clear selection.
        m_attributeView->setEnabled(false);
    }
}


void DockableAttributePanel::ItemNameChanged(CBaseLibraryItem* item, const QString& oldName, const QString& currentName, const QString newLib)
{
    CRY_ASSERT(item);

    QString oldFullName = item->GetLibrary()->GetName(); // Grab old library
    oldFullName.append(".");
    oldFullName.append(oldName);
    QString prevName = oldFullName;

    QString nextTabTitle = newLib.isEmpty() ? QString(item->GetLibrary()->GetName()) + "." + currentName : newLib + "." + currentName;

    int tabIndex = FindItemInTabs(prevName);
    if (tabIndex != -1)
    {
        ParticleTabData tabData = m_openParticleTabBar->tabData(tabIndex).value<ParticleTabData>();
        tabData.m_libraryItemName = nextTabTitle;
        tabData.m_libraryName = newLib.isEmpty() ? QString(item->GetLibrary()->GetName()) : newLib;
        QVariant d;
        d.setValue(tabData);
        m_openParticleTabBar->setTabData(tabIndex, d); //Update the tab data
        m_openParticleTabBar->setTabText(tabIndex, nextTabTitle); //Update the tab title name
    }
}

void DockableAttributePanel::UpdateItemName(const QString& fullOldName, const QString& fullNewName)
{
    QStringList newNameList = fullNewName.split(".");
    QString newLibName = newNameList.first();
    QString prevName = fullOldName;
    int tabIndex = FindItemInTabs(prevName);

    if (tabIndex != -1)
    {
        ParticleTabData tabData = m_openParticleTabBar->tabData(tabIndex).value<ParticleTabData>();
        tabData.m_libraryItemName = fullNewName;
        tabData.m_libraryName = newLibName;
        QVariant d;
        d.setValue(tabData);
        m_openParticleTabBar->setTabData(tabIndex, d); //Update the tab data
        m_openParticleTabBar->setTabText(tabIndex, fullNewName); //Update the tab title name
    }
}

void DockableAttributePanel::TabSelectionChange(int index)
{
    if (m_IgnoreAttributeRefresh)
    {
        return;
    }

    if (index == -1)
    {
        //There is no tab to change to
        return;
    }

    if (m_openParticleTabBar->tabData(index).canConvert<ParticleTabData>())
    {
        ParticleTabData tabData = m_openParticleTabBar->tabData(index).value<ParticleTabData>();
        QString tabTitle = m_openParticleTabBar->tabText(index);
        qDebug() << "Particle Editor: changed to particle" << tabTitle << "via tab" << index;

        CParticleItem* libItem = static_cast<CParticleItem*>(m_libraryManager->FindItemByName(tabData.m_libraryItemName));
        m_attributeView->SetCurrentItem(libItem);
        if (libItem)
        {
            //set the attributeview's selected emitter by name
            emit SignalTabSelectionChanged(tabData.m_libraryName, QString(libItem->GetName()));
        }
    }
}

void DockableAttributePanel::ImportPanelFromQString(QString filedata)
{
    m_attributeView->ImportPanel(filedata, false);
}

void DockableAttributePanel::TabClosing(int index)
{
    CRY_ASSERT(m_openParticleTabBar);
    CRY_ASSERT(m_attributeView);

    if (m_TabBarDynamicTabIndex != -1)
    {
        if (m_TabBarDynamicTabIndex == index)
        {
            m_TabBarDynamicTabIndex = -1; //reset the dynamictabindex to needing a new tab.
        }
        else if (m_TabBarDynamicTabIndex > index)
        {
            m_TabBarDynamicTabIndex--; //we are about to remove an index that is under this stored index so that means it will be reduced by 1
        }
    }

    m_openParticleTabBar->removeTab(index);
    if (m_openParticleTabBar->count() == 0)
    {
        m_openParticleTabBar->repaint(); //Needed to ensure proper redraw when last tab is removed
        m_attributeView->setEnabled(false);
        m_attributeView->ShowDefaultView();
        SignalTabSelectionChanged("", "");
    }
}

void DockableAttributePanel::TabMoved(int from, int to)
{
    // the logic here is based on the tab that has moved not the tab that is grabbed is moving from (int) to(int)
    if (m_TabBarDynamicTabIndex == to)
    {
        m_TabBarDynamicTabIndex = from;
    }
}

void DockableAttributePanel::TabShowContextMenu(const QPoint& pos)
{
    CRY_ASSERT(m_openParticleTabBar);

    int index = m_openParticleTabBar->tabAt(pos);
    if (index != -1)
    {
        ContextMenu tabBarContextMenu(this);
        tabBarContextMenu.clear();

        ParticleTabData tabData = m_openParticleTabBar->tabData(index).value<ParticleTabData>();
        emit SignalPopulateTabBarContextMenu(tabData.m_libraryName, tabData.m_libraryItemName, &tabBarContextMenu);
        tabBarContextMenu.exec(m_openParticleTabBar->mapToGlobal(pos));
    }
}

QMenu* DockableAttributePanel::GetTitleBarMenu()
{
    CRY_ASSERT(m_titleBarMenu);
    m_titleBarMenu->clear();
    emit SignalPopulateTitleBarMenu(m_titleBarMenu);
    return m_titleBarMenu;
}

DockWidgetTitleBar* DockableAttributePanel::CreateTabBar()
{
    DockWidgetTitleBar* propertiesTabBar = new DockWidgetTitleBar(this);
    propertiesTabBar->setObjectName("AttributeTabTitleBar");
    m_openParticleTabBar = propertiesTabBar->SetupFluidTabBar();
    m_openParticleTabBar->setContextMenuPolicy(Qt::CustomContextMenu);
    m_openParticleTabBar->setTabsClosable(false); //FluidTabBar handles close buttons manually
    m_openParticleTabBar->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Maximum);

    //Callbacks
    connect(m_openParticleTabBar, &QTabBar::currentChanged, this, &DockableAttributePanel::TabSelectionChange);
    connect(m_openParticleTabBar, &QTabBar::tabCloseRequested, this, &DockableAttributePanel::TabClosing);
    connect(m_openParticleTabBar, &QTabBar::tabMoved, this, &DockableAttributePanel::TabMoved);
    connect(m_openParticleTabBar, &FluidTabBar::customContextMenuRequested, this, &DockableAttributePanel::TabShowContextMenu);

    return propertiesTabBar;
}

void DockableAttributePanel::RefreshOpenTabColors()
{
    CRY_ASSERT(m_openParticleTabBar);
    for (int tabIdx = 0; tabIdx < m_openParticleTabBar->count(); tabIdx++)
    {
        if (m_openParticleTabBar->tabData(tabIdx).canConvert<ParticleTabData>())
        {
            ParticleTabData tabData = m_openParticleTabBar->tabData(tabIdx).value<ParticleTabData>();
            CParticleItem* libItem = static_cast<CParticleItem*>(m_libraryManager->FindItemByName(tabData.m_libraryItemName));
            CRY_ASSERT(libItem);
            CRY_ASSERT(libItem->GetType() == EDB_TYPE_PARTICLE);
            m_openParticleTabBar->setTabTextColor(tabIdx, GetTabTextColorFor(static_cast<CParticleItem*>(libItem)));
        }
    }
}

int DockableAttributePanel::FindItemInTabs(QString& itemName) const
{
    CRY_ASSERT(m_openParticleTabBar);
    int tabIndex = -1;
    for (int i = 0; i < m_openParticleTabBar->count(); i++)
    {
        if (m_openParticleTabBar->tabData(i).canConvert<ParticleTabData>())
        {
            ParticleTabData tabData = m_openParticleTabBar->tabData(i).value<ParticleTabData>();
            if (tabData.m_libraryItemName == itemName)
            {
                tabIndex = i;
                break;
            }
        }
    }
    return tabIndex;
}

void DockableAttributePanel::SelectTab(unsigned int tabIndex)
{
    CRY_ASSERT(m_openParticleTabBar);
    CRY_ASSERT(tabIndex < m_openParticleTabBar->count());

    m_openParticleTabBar->setCurrentIndex(tabIndex);
}

void DockableAttributePanel::AddToDynamicTab(QString& tabTitle, ParticleTabData& data)
{
    CRY_ASSERT(m_openParticleTabBar);
    int tabIndex = -1;
    //Item is not in a tab yet so add it to the "dynamic" tab
    if (m_TabBarDynamicTabIndex != -1) //"dynamic" tab is valid
    {
        tabIndex = m_TabBarDynamicTabIndex;
        m_openParticleTabBar->setTabText(tabIndex, tabTitle); //update the name so we dont show previous name
    }
    else //Create a new "dynamic" tab
    {
        tabIndex = m_openParticleTabBar->addTab(tabTitle);
        data.m_isNewTab = true;//Mark the tab to be newly created, otherwise the m_openParticleTabBar::currentChanged event will cause an extra reload
        m_TabBarDynamicTabIndex = tabIndex;
    }
    QVariant d;
    d.setValue(data);
    m_openParticleTabBar->setTabData(tabIndex, d);
    CParticleItem* libItem = static_cast<CParticleItem*>(m_libraryManager->FindItemByName(data.m_libraryItemName));
    m_openParticleTabBar->setTabTextColor(tabIndex, GetTabTextColorFor(static_cast<CParticleItem*>(libItem)));
    SelectTab(tabIndex);//Select the tab ...
}

QColor DockableAttributePanel::GetTabTextColorFor(CParticleItem* item) const
{
    CRY_ASSERT(item);
    CRY_ASSERT(item->GetType() == EDB_TYPE_PARTICLE);
    QColor retval = Qt::red;
    if (GetEnabledParameterValue(item))
    {
        retval = m_enabledTabTextColor;
    }
    else
    {
        retval = m_disabledTabTextColor;
    }
    return retval;
}

void DockableAttributePanel::SetOnVariableChangeCallbackRecurse(IVariableContainer* vars)
{
    CRY_ASSERT(vars);
    for (int i = 0; i < vars->GetNumVariables(); i++)
    {
        IVariable* var = vars->GetVariable(i);
        CRY_ASSERT(var);
        var->AddOnSetCallback(functor(*this, &DockableAttributePanel::OnVariableChange));
        SetOnVariableChangeCallbackRecurse(var);
    }
}

void DockableAttributePanel::OnVariableChange(IVariable* var)
{
    if (m_IgnoreAttributeRefresh)
    {
        return;
    }

    CRY_ASSERT(m_openParticleTabBar);
    CRY_ASSERT(m_pParticleUI);
    int curTab = m_openParticleTabBar->currentIndex();
    if (curTab != -1)
    {
        CRY_ASSERT(m_openParticleTabBar->tabData(curTab).canConvert<ParticleTabData>());
        ParticleTabData tabData = m_openParticleTabBar->tabData(curTab).value<ParticleTabData>();

        CParticleItem* particleItem = static_cast<CParticleItem*>(m_libraryManager->FindItemByName(tabData.m_libraryItemName));
        CRY_ASSERT(particleItem);

        //if any of these are true particleitem is invalid, return to prevent crashing
        if (!particleItem)
        {
            return;
        }
        if (particleItem->GetFullName().isEmpty() || !particleItem->GetEffect() || !particleItem->GetLibrary())
        {
            return;
        }

        particleItem->SetModified();
        GetIEditor()->SetModifiedFlag();

        m_pParticleUI->SetToParticles(particleItem, m_currentLod);

        // If enabled state is changed, refresh UI active icons ... special case for handling of visualization changes in other widgets.
        if (QString::compare(var->GetName(), "Enabled") == 0)
        {
            emit SignalEnabledParameterChanged(tabData.m_libraryName, tabData.m_libraryItemName);
            m_openParticleTabBar->setTabTextColor(curTab, GetTabTextColorFor(particleItem));//NOTE: the above SetToParticles should sync the value as the "changed" version.
        }
        RefreshGroupNodeSettings();
        //POSSIBLE LEGACY ONLY SYNC USAGE HERE
        emit SignalParameterChanged(tabData.m_libraryName, tabData.m_libraryItemName);
        //POSSIBLE LEGACY ONLY SYNC USAGE HERE
    }
}


void DockableAttributePanel::RefreshCurrentParameterUI()
{
    EditorUIPlugin::ScopedSuspendUndoPtr suspendUndo;
    EBUS_EVENT_RESULT(suspendUndo, EditorLibraryUndoRequestsBus, AddScopedSuspendUndo);

    m_pParticleUI->SetFromParticles(m_attributeView->GetCurrentItem(), m_currentLod);
}

void DockableAttributePanel::RefreshParameterUI(CParticleItem* item, SLodInfo* lod)
{
    CRY_ASSERT(item);
    CRY_ASSERT(item->GetLibrary());
    CRY_ASSERT(m_attributeView);
    CRY_ASSERT(m_pParticleUI);
    CRY_ASSERT(m_attributeView->getPanelWidget());
    CRY_ASSERT(GetIEditor());

    EditorUIPlugin::ScopedSuspendUndoPtr suspendUndo;
    EBUS_EVENT_RESULT(suspendUndo, EditorLibraryUndoRequestsBus, AddScopedSuspendUndo);
    
    m_IgnoreAttributeRefresh = true;
    {
        //Building the UI
        if (m_attributeView->getPanelWidget()->isEmpty())
        {
            m_attributeView->Clear();
            QString particlePath = QString().asprintf("%s.%s", item->GetLibrary()->GetName().toUtf8().constData(), item->GetName().toUtf8().constData());
            m_attributeView->InitConfiguration(particlePath);
            LoadSessionState(); //configure the UI the way the user wants it to be.
        }
        else
        {
            SaveSessionState();
        }

        m_pParticleUI->SetFromParticles(item, lod);
    }
    m_IgnoreAttributeRefresh = false;

    m_attributeView->HideDefaultView();
    m_attributeView->setEnabled(true);
    m_attributeView->SetCurrentItem(item);
    RefreshGroupNodeSettings();
}

void DockableAttributePanel::RefreshCurrentTab()
{
    //closes current tab then reopens tab and inserts it to current index
    int index = m_openParticleTabBar->currentIndex();
    if (m_openParticleTabBar->tabData(index).canConvert<ParticleTabData>())
    {
        ParticleTabData tabData = m_openParticleTabBar->tabData(index).value<ParticleTabData>();
        QString tabTitle = m_openParticleTabBar->tabText(index);
        CParticleItem* libItem = static_cast<CParticleItem*>(m_libraryManager->FindItemByName(tabData.m_libraryItemName));
        if (libItem != nullptr)
        {
            QString itemName = libItem->GetName();
            emit SignalTabSelectionChanged(tabData.m_libraryName, itemName);
        }
        else
        {
            CloseTab(tabTitle);
        }
    }
}

QString DockableAttributePanel::GetCurrentTabText()
{
    int index = m_openParticleTabBar->currentIndex();
    if (index == -1)
    {
        return "";
    }
    return m_openParticleTabBar->tabText(index);
}

void DockableAttributePanel::CloseTab(const QString& name)
{
    m_openParticleTabBar->CloseTab(name);
}

void DockableAttributePanel::OnEnabledToggleTriggered()
{
    if (!GetIEditor()->GetParticleUtils()->HotKey_IsEnabled())
    {
        return;
    }
    IVariable* var = m_attributeView->GetVarFromPath("Emitter.Enabled");
    if (var != nullptr)
    {
        bool state = false;
        var->Get(state);
        var->Set(!state);
    }
}

void DockableAttributePanel::OnInsertCommentTriggered()
{
    if (!GetIEditor()->GetParticleUtils()->HotKey_IsEnabled())
    {
        return;
    }
    m_attributeView->FocusVar("Emitter.Comment");
}

void DockableAttributePanel::CloseAllTabs()
{
    m_openParticleTabBar->CloseAll();
}

void DockableAttributePanel::RefreshGroupNodeSettings()
{
    IVariable* groupVar = m_attributeView->GetVarFromPath("GroupNode.Group");
    if (!groupVar)
    {
        return;
    }
    bool isGroup = false;
    groupVar->Get(isGroup);
    if (isGroup)
    {
        m_attributeView->HideAllButGroup("Group&&Comment");
    }
    else
    {
        m_attributeView->ShowAllButGroup("Group");
    }
}

void DockableAttributePanel::PassThroughSignalBuildPanelList(QMenu* menu)
{
    emit SignalBuildCustomAttributeList(menu);
}

void DockableAttributePanel::PassThroughSignalAddPreset(QString panelName, QString data)
{
    emit SignalAddPreset(panelName, data);
}

void DockableAttributePanel::OnItemUndoPoint(const QString& itemName)
{
    emit SignalItemUndoPoint(itemName, true, m_currentLod);
}

#include <QT/DockableAttributePanel.moc>