﻿// TortoiseSVN - a Windows shell extension for easy version control

// Copyright (C) 2009, 2021 - TortoiseSVN

// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software Foundation,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
#include "stdafx.h"
#include "RevisionGraphState.h"

#ifdef _DEBUG
// ReSharper disable once CppInconsistentNaming
#    define new DEBUG_NEW
#    undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

// construction / destruction

CRevisionGraphState::CRevisionGraphState()
    : fetchedWCState(false)
    , options(&nodeStates)
{
}

CRevisionGraphState::~CRevisionGraphState()
{
}

// basic, synchronized data read access

CSyncPointer<const CAllRevisionGraphOptions> CRevisionGraphState::GetOptions() const
{
    CSingleLock lock(&mutex);
    return CSyncPointer<const CAllRevisionGraphOptions>(&mutex, &options, false);
}

CSyncPointer<const CFullHistory> CRevisionGraphState::GetFullHistory() const
{
    CSingleLock lock(&mutex);
    return CSyncPointer<const CFullHistory>(&mutex, fullHistory.get(), false);
}

CSyncPointer<const CFullGraph> CRevisionGraphState::GetFullGraph() const
{
    CSingleLock lock(&mutex);
    return CSyncPointer<const CFullGraph>(&mutex, fullGraph.get(), false);
}

CSyncPointer<const CVisibleGraph> CRevisionGraphState::GetVisibleGraph() const
{
    CSingleLock lock(&mutex);
    return CSyncPointer<const CVisibleGraph>(&mutex, visibleGraph.get(), false);
}

CSyncPointer<const ILayoutNodeList> CRevisionGraphState::GetNodes() const
{
    CSingleLock lock(&mutex);
    return CSyncPointer<const ILayoutNodeList>(&mutex, layout.get() == nullptr ? nullptr : layout->GetNodes(), true);
}

CSyncPointer<const ILayoutConnectionList> CRevisionGraphState::GetConnections() const
{
    CSingleLock lock(&mutex);
    return CSyncPointer<const ILayoutConnectionList>(&mutex, layout.get() == nullptr ? nullptr : layout->GetConnections(), true);
}

CSyncPointer<const ILayoutTextList> CRevisionGraphState::GetTexts() const
{
    CSingleLock lock(&mutex);
    return CSyncPointer<const ILayoutTextList>(&mutex, layout.get() == nullptr ? nullptr : layout->GetTexts(), true);
}

CSyncPointer<const ILayoutRectList> CRevisionGraphState::GetTrees() const
{
    CSingleLock lock(&mutex);
    return CSyncPointer<const ILayoutRectList>(&mutex, layout.get() == nullptr ? nullptr : layout->GetTrees(), true);
}

bool CRevisionGraphState::GetFetchedWCState() const
{
    return fetchedWCState;
}

CString CRevisionGraphState::GetLastErrorMessage() const
{
    CSingleLock lock(&mutex);
    return lastErrorMessage;
}

CSyncPointer<CAllRevisionGraphOptions> CRevisionGraphState::GetOptions()
{
    CSingleLock lock(&mutex);
    return CSyncPointer<CAllRevisionGraphOptions>(&mutex, &options, false);
}

CSyncPointer<const CGraphNodeStates> CRevisionGraphState::GetNodeStates() const
{
    CSingleLock lock(&mutex);
    return CSyncPointer<const CGraphNodeStates>(&mutex, &nodeStates, false);
}

CSyncPointer<CGraphNodeStates> CRevisionGraphState::GetNodeStates()
{
    CSingleLock lock(&mutex);
    return CSyncPointer<CGraphNodeStates>(&mutex, &nodeStates, false);
}

CSyncPointer<const CRevisionGraphState::TVisibleGlyphs> CRevisionGraphState::GetVisibleGlyphs() const
{
    CSingleLock lock(&mutex);
    return CSyncPointer<const TVisibleGlyphs>(&mutex, &visibleGlyphs, false);
}

CSyncPointer<CRevisionGraphState::TVisibleGlyphs> CRevisionGraphState::GetVisibleGlyphs()
{
    CSingleLock lock(&mutex);
    return CSyncPointer<TVisibleGlyphs>(&mutex, &visibleGlyphs, false);
}

CSyncPointer<SVN> CRevisionGraphState::GetSVN() const
{
    CSingleLock lock(&mutex);
    return CSyncPointer<SVN>(&mutex, fullHistory.get() == nullptr ? nullptr : &fullHistory->GetSVN(), false);
}

// basic, synchronized data write access

void CRevisionGraphState::SetQueryResult(std::unique_ptr<CFullHistory>& newHistory, std::unique_ptr<CFullGraph>& newFullGraph, bool newFetchedWCState)
{
    CSingleLock lock(&mutex);

    // delete the old data first before, potentially partially,
    // rerouting the references to the new data

    CGraphNodeStates::TSavedData oldStates = nodeStates.SaveData();
    nodeStates.ResetFlags(UINT_MAX);
    visibleGlyphs.clear();

    layout.reset();
    visibleGraph.reset();
    fullGraph.reset();
    fullHistory.reset();

    fullHistory.reset(newHistory.release());
    fullGraph.reset(newFullGraph.release());

    fetchedWCState = newFetchedWCState;

    nodeStates.LoadData(oldStates, fullGraph.get());
}

void CRevisionGraphState::SetAnalysisResult(std::unique_ptr<CVisibleGraph>& newVisibleGraph, std::unique_ptr<CStandardLayout>& newLayout)
{
    CSingleLock lock(&mutex);

    visibleGlyphs.clear();

    layout.reset();
    visibleGraph.reset();

    visibleGraph.reset(newVisibleGraph.release());
    layout.reset(newLayout.release());
}

void CRevisionGraphState::SetLastErrorMessage(const CString& message)
{
    CSingleLock lock(&mutex);
    lastErrorMessage = message;
}

// convenience methods

CRect CRevisionGraphState::GetGraphRect() const
{
    CSingleLock lock(&mutex);
    return layout.get() != nullptr
               ? layout->GetRect()
               : CRect(0, 0, 0, 0);
}

int CRevisionGraphState::GetNodeCount() const
{
    CSingleLock lock(&mutex);

    return visibleGraph.get() != nullptr
               ? static_cast<int>(visibleGraph->GetNodeCount())
               : 0;
}

svn_revnum_t CRevisionGraphState::GetHeadRevision() const
{
    CSingleLock lock(&mutex);

    return fullHistory.get() != nullptr
               ? fullHistory->GetHeadRevision()
               : 0;
}

CString CRevisionGraphState::GetRepositoryRoot() const
{
    CSingleLock lock(&mutex);

    return fullHistory.get() != nullptr
               ? fullHistory->GetRepositoryRoot()
               : CString();
}

CString CRevisionGraphState::GetRepositoryUUID() const
{
    CSingleLock lock(&mutex);

    return fullHistory.get() != nullptr
               ? fullHistory->GetRepositoryUUID()
               : CString();
}

size_t CRevisionGraphState::GetTreeCount() const
{
    CSingleLock lock(&mutex);

    if (layout.get() == nullptr)
        return 0;

    CSyncPointer<const ILayoutRectList> trees(&mutex, layout->GetTrees(), true);
    return trees->GetCount();
}

bool CRevisionGraphState::PromptShown() const
{
    CSingleLock lock(&mutex);

    return fullHistory.get() != nullptr
               ? fullHistory->GetSVN().PromptShown()
               : false;
}
