/***************************************************************************
**
**  This file is part of GeopsyCore.
**
**  GeopsyCore 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 3 of the License, or
**  (at your option) any later version.
**
**  GeopsyCore 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 Foobar.  If not, see <http://www.gnu.org/licenses/>
**
**  See http://www.geopsy.org for more information.
**
**  Created: 2010-08-02
**  Copyright: 2010-2019
**    Marc Wathelet (LGIT, Grenoble, France)
**
***************************************************************************/

#include "MetaDataMap.h"
#include "MetaData.h"
#include "MetaDataFactory.h"

namespace GeopsyCore {

  /*!
    \class MetaDataMap MetaDataMap.h
    \brief Brief description of class still missing

    Full description of class still missing
  */

  MetaDataMap::~MetaDataMap()
  {
    TRACE;
    clear();
  }

  void MetaDataMap::clear()
  {
    TRACE;
    int n=count();
    for(int i=0; i<n; i++) {
      MetaData::removeReference(at(i));
    }
    SortedVector<int, MetaData>::clear();
  }

  void MetaDataMap::operator=(const MetaDataMap& o)
  {
    TRACE;
    clear();
    add(o);
  }

  /*!
    Add meta data \a d. It takes ownership of \a d.
  */
  void MetaDataMap::add(MetaData * d)
  {
    TRACE;
    if(contains(d->id())) {
      qWarning("Add meta data: '%s' already exists.", d->xml_tagName().toLatin1().data());
    } else {
      insert(d);
      d->addReference();
    }
  }

  /*!
    Adds metadata from another map. Called only from operator=() and SignalDatabase::add.
  */
  void MetaDataMap::add(const MetaDataMap& o)
  {
    TRACE;
    int n=o.count();
    reserve(count()+n);
    for(int i=0; i<n; i++) {
      MetaData * d=o.at(i);
      if(d->copyAllowed()) {
        if(d->referenceCount()==1) {
          MetaData *d1=d->clone(); // Not shared meta data, make a copy
          *d1=*d;
          d=d1;
        }
        add(d);
      }
    }
  }

  /*!
    Remove meta data with \a id. Meta data is deleted if it is not shared.
  */
  void MetaDataMap::remove(int id)
  {
    TRACE;
    int index=firstIndexOf(id);
    if(index>-1) {
      MetaData * d=at(index);
      SortedVector<int, MetaData>::remove(index);
      MetaData::removeReference(d);
    }
  }

  /*!
    \fn bool MetaDataMap::hasData(int id) const

    Returns true if metadata with \a id exists.
  */

  /*!
    Returns a pointer to meta data \a id. If it does not exist for signal, creates a new instance.
  */
  MetaData * MetaDataMap::data(int id)
  {
    TRACE;
    int index=firstIndexOf(id);
    if(index>-1) {
      return at(index);
    } else {
      MetaData * d=MetaDataFactory::instance()->create(id);
      if(d) {
        insert(d);
        d->addReference();
        return d;
      } else {
        return nullptr;
      }
    }
  }

  /*!
    Returns a pointer to meta data \a id. If it does exist for signal, returns the default instance.
  */
  const MetaData * MetaDataMap::data(int id) const
  {
    TRACE;
    int index=firstIndexOf(id);
    if(index>-1) {
      return at(index);
    } else {
      // Creates a temporary object just to use the virtual table
      MetaData * td=MetaDataFactory::instance()->create(id);
      if(td) {
        const MetaData& d=td->defaultValue();
        delete td; // Default value is always a static member no risk with delete
        return &d;
      } else {
        return nullptr;
      }
    }
  }

} // namespace GeopsyCore
