// $Id: gc_file.cpp,v 1.39 2018/01/03 21:32:55 mkkuhner Exp $

/*
Copyright 2002-2005 Mary K. Kuhner, Peter Beerli, and Joseph Felsenstein

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

*/

/* Authors: Mary Kuhner, Jon Yamato, and Joseph Felsenstein */


#include <cassert>

#include "Converter_LamarcDS.h"
#include "gc_data.h"
#include "gc_datastore.h"
#include "gc_errhandling.h"
#include "gc_file.h"
#include "gc_strings.h"
#include "gc_strings_structures.h"
#include "gc_structures_err.h"
#include "wx/filename.h"
#include "wx/log.h"

//------------------------------------------------------------------------------------

std::map<wxString,wxString> GCFile::s_fileNameMap;

//------------------------------------------------------------------------------------

GCFile::GCFile( GCDataStore &       dataStoreRef,
                wxString            name)
    :
    m_dataStore(dataStoreRef),
    m_fullPathFileName(name),
    m_parses(NULL)
{
    std::map<wxString,wxString>::const_iterator iter = s_fileNameMap.find(GetShortName());
    if(iter != s_fileNameMap.end())
    {
        wxString oldFileName = (*iter).second;
        wxString msg;
        if(oldFileName == GetName())
        {
            throw duplicate_file_error(oldFileName);
        }
        else
        {
            throw duplicate_file_base_name_error(oldFileName);
        }
    }
    else
    {
        s_fileNameMap[GetShortName()] = GetName();
    }
}

GCFile::~GCFile()
{
    std::map<wxString,wxString>::iterator iter = s_fileNameMap.find(GetShortName());
    if(iter != s_fileNameMap.end())
    {
        s_fileNameMap.erase(iter);
    }

    if(m_parses != NULL)
    {
        m_parses->NukeContents();
        delete(m_parses);
    }
}

void
GCFile::SetParses(GCParseVec * parses)
{
    m_parses = parses;
}

wxString
GCFile::GetName() const
{
    wxFileName fname(m_fullPathFileName);
    return fname.GetFullPath();
}

wxString
GCFile::GetShortName() const
{
    wxFileName fname(m_fullPathFileName);
    return fname.GetFullName(); // "FullName == file name + extention
}

const GCParse &
GCFile::GetParse(size_t choice) const
{
    assert(m_parses != NULL);
    assert(m_parses->size() > choice);
    const GCParse * parseP = (*m_parses)[choice];
    assert(parseP != NULL);
    return *parseP;
}

size_t
GCFile::GetParseCount() const
{
    if(m_parses == NULL) return 0;
    return m_parses->size();
}

void
GCFile::DebugDump(wxString prefix) const
{
    wxLogDebug("%sfile (id %d) %s", // EWDUMPOK
               prefix.c_str(),
               (int)GetId(),
               GetName().c_str());
    for(GCParseVec::const_iterator i = m_parses->begin(); i != m_parses->end(); i++)
    {
        const GCParse & parse = **i;
        parse.DebugDump(prefix+gcstr::indent);
    }
}

const GCParse &
GCFile::GetParse(   GCFileFormat        format,
                    gcGeneralDataType   dataType,
                    GCInterleaving      interleaving) const
{
    if(m_parses != NULL)
    {
        for(size_t index = 0; index < m_parses->size(); index++)
        {
            GCParse & parse = *((*m_parses)[index]);
            if( parse.GetFormat() == format )
            {
                if( parse.GetInterleaving() == interleaving_MOOT ||
                    parse.GetInterleaving() == interleaving)
                {
                    if( parse.GetDataType().CompatibleWith(dataType) )
                    {
                        return parse;
                    }
                }
            }
        }
    }
    wxString fileFmtStr     = ToWxString(format);
    wxString dataTypeStr    = ToWxString(dataType);
    wxString interleaveStr  = ToWxString(interleaving);
    wxString msg = wxString::Format(gcerr::noSuchParse,
                                    GetName().c_str(),
                                    fileFmtStr.c_str(),
                                    dataTypeStr.c_str(),
                                    interleaveStr.c_str());
    gc_data_error e(msg.c_str());
    throw e;
}

bool
GCFileCompare::operator()(const GCFile* p1, const GCFile* p2)
{
    const wxString name1 = p1->GetName();
    const wxString name2 = p2->GetName();
    assert( (p1->GetId() != p2->GetId()) || (name1==name2));
    return (name1 < name2);
}

gcIdSet
GCFile::IdsOfAllBlocks() const
{
    gcIdSet retSet;
    for(size_t i=0; i < m_parses->size(); i++)
    {
        const GCParse & parse = *((*m_parses)[i]);
        gcIdSet pSet = parse.IdsOfAllBlocks();
        retSet.insert(pSet.begin(),pSet.end());
    }
    return retSet;
}

gcIdSet
GCFile::IdsOfAllParses() const
{
    gcIdSet retSet;
    for(size_t i=0; i < m_parses->size(); i++)
    {
        const GCParse & parse = *((*m_parses)[i]);
        retSet.insert(parse.GetId());
    }
    return retSet;
}

gcGeneralDataType
GCFile::GetGeneralDataType() const
{
    gcGeneralDataType myType;

    for(size_t i=0; i < GetParseCount(); i++)
    {
        const GCParse & parse = GetParse(i);
        myType.Union(parse.GetDataType());
    }
    return myType;

}

wxString
GCFile::GetDataTypeString() const
{
    gcGeneralDataType myType = GetGeneralDataType();
    return ToWxString(myType).c_str();
}

GCFileFormat
GCFile::GetFormat() const
{
    GCFileFormat myType = format_NONE_SET;
    for(size_t i=0; i < GetParseCount(); i++)
    {
        const GCParse & parse = GetParse(i);
        if (i == 0)
        {
            myType = parse.GetFormat();
        }
        else
        {
            if(myType != parse.GetFormat())
            {
                return format_NONE_SET;
            }
        }
    }
    return myType;
}

wxString
GCFile::GetFormatString() const
{
    GCFileFormat myType = format_NONE_SET;
    return ToWxString(myType).c_str();
}

GCInterleaving
GCFile::GetInterleaving() const
{
    GCInterleaving myType = interleaving_NONE_SET;
    for(size_t i=0; i < GetParseCount(); i++)
    {
        const GCParse & parse = GetParse(i);
        if (i == 0)
        {
            myType = parse.GetInterleaving();
        }
        else
        {
            if(myType != parse.GetInterleaving())
            {
                return interleaving_NONE_SET;
            }
        }
    }
    return myType;

}

wxString
GCFile::GetInterleavingString() const
{
    GCInterleaving myType = GetInterleaving();
    return ToWxString(myType).c_str();
}

//____________________________________________________________________________________
