﻿// TortoiseMerge - a Diff/Patch program

// Copyright (C) 2006-2007, 2011-2014, 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 "WorkingFile.h"
#include "PathUtils.h"
#include "resource.h"
#include "SmartHandle.h"

CWorkingFile::CWorkingFile()
{
    ClearStoredAttributes();
}

CWorkingFile::~CWorkingFile()
{
}

void CWorkingFile::SetFileName(const CString& newFilename)
{
    m_sFilename = newFilename;
    m_sFilename.Replace('/', '\\');
    m_sDescriptiveName.Empty();
    ClearStoredAttributes();
}

void CWorkingFile::SetDescriptiveName(const CString& newDescName)
{
    m_sDescriptiveName = newDescName;
}

CString CWorkingFile::GetDescriptiveName() const
{
    if (m_sDescriptiveName.IsEmpty())
    {
        CString sDescriptiveName  = CPathUtils::GetFileNameFromPath(m_sFilename);
        WCHAR   pathbuf[MAX_PATH] = {0};
        PathCompactPathEx(pathbuf, sDescriptiveName, 50, 0);
        sDescriptiveName = pathbuf;
        return sDescriptiveName;
    }
    return m_sDescriptiveName;
}

CString CWorkingFile::GetReflectedName() const
{
    return m_sReflectedName;
}

void CWorkingFile::SetReflectedName(const CString& newReflectedName)
{
    m_sReflectedName = newReflectedName;
}

//
// Make an empty file with this name
void CWorkingFile::CreateEmptyFile() const
{
    CAutoFile hFile = CreateFile(m_sFilename, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
}

// Move the details of the specified file to the current one, and then mark the specified file
// as out of use
void CWorkingFile::TransferDetailsFrom(CWorkingFile& rightHandFile)
{
    // We don't do this to files which are already in use
    ASSERT(!InUse());

    m_sFilename        = rightHandFile.m_sFilename;
    m_sDescriptiveName = rightHandFile.m_sDescriptiveName;
    rightHandFile.SetOutOfUse();
    m_attribs = rightHandFile.m_attribs;
}

CString CWorkingFile::GetWindowName() const
{
    CString sErrMsg;
    // TortoiseMerge allows non-existing files to be used in a merge
    // Inform the user (in a non-intrusive way) if a file is absent
    if (!this->Exists())
    {
        sErrMsg = CString(MAKEINTRESOURCE(IDS_NOTFOUNDVIEWTITLEINDICATOR));
    }

    if (m_sDescriptiveName.IsEmpty())
    {
        // We don't have a proper name - use the filename part of the path
        // return the filename part of the path.
        return CPathUtils::GetFileNameFromPath(m_sFilename) + L" " + sErrMsg;
    }
    else if (sErrMsg.IsEmpty())
    {
        return m_sDescriptiveName;
    }
    return m_sDescriptiveName + L" " + sErrMsg;
}

bool CWorkingFile::Exists() const
{
    return (!!PathFileExists(m_sFilename));
}

void CWorkingFile::SetOutOfUse()
{
    m_sFilename.Empty();
    m_sDescriptiveName.Empty();
    ClearStoredAttributes();
}

bool CWorkingFile::HasSourceFileChanged() const
{
    if (!InUse())
    {
        return false;
    }
    WIN32_FILE_ATTRIBUTE_DATA attribs = {0};
    if (PathFileExists(m_sFilename))
    {
        if (GetFileAttributesEx(m_sFilename, GetFileExInfoStandard, &attribs))
        {
            if ((m_attribs.nFileSizeHigh != attribs.nFileSizeHigh) ||
                (m_attribs.nFileSizeLow != attribs.nFileSizeLow))
                return true;
            return ((CompareFileTime(&m_attribs.ftCreationTime, &attribs.ftCreationTime) != 0) ||
                    (CompareFileTime(&m_attribs.ftLastWriteTime, &attribs.ftLastWriteTime) != 0));
        }
    }

    return false;
}

void CWorkingFile::StoreFileAttributes()
{
    ClearStoredAttributes();

    WIN32_FILE_ATTRIBUTE_DATA attribs = {0};
    if (GetFileAttributesEx(m_sFilename, GetFileExInfoStandard, &attribs))
    {
        m_attribs = attribs;
    }
}

void CWorkingFile::ClearStoredAttributes()
{
    static const WIN32_FILE_ATTRIBUTE_DATA attribsEmpty = {0};
    m_attribs                                           = attribsEmpty;
}

bool CWorkingFile::IsReadonly() const
{
    return (m_attribs.dwFileAttributes != INVALID_FILE_ATTRIBUTES) && (m_attribs.dwFileAttributes & FILE_ATTRIBUTE_READONLY);
}
