// Aseprite Document Library
// Copyright (c) 2019-2023 Igara Studio S.A.
// Copyright (c) 2001-2016 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.

#ifdef HAVE_CONFIG_H
  #include "config.h"
#endif

#include "doc/cels_range.h"

#include "doc/cel.h"
#include "doc/layer.h"
#include "doc/sprite.h"

namespace doc {

CelsRange::CelsRange(const Sprite* sprite, const SelectedFrames& selFrames, const Flags flags)
  : m_selFrames(selFrames)
  , m_begin(sprite, m_selFrames, flags)
  , m_end(m_selFrames)
{
}

CelsRange::iterator::iterator(const SelectedFrames& selFrames)
  : m_cel(nullptr)
  , m_selFrames(selFrames)
  , m_frameIterator(selFrames.begin())
{
}

CelsRange::iterator::iterator(const Sprite* sprite,
                              const SelectedFrames& selFrames,
                              const CelsRange::Flags flags)
  : m_cel(nullptr)
  , m_selFrames(selFrames)
  , m_frameIterator(selFrames.begin())
  , m_flags(flags)
{
  // Get first cel
  Layer* layer = sprite->root()->firstLayerInWholeHierarchy();
  while (layer && !m_cel) {
    if (layer->isImage()) {
      m_frameIterator = m_selFrames.begin();
      auto endFrame = m_selFrames.end();
      for (; m_frameIterator != endFrame; ++m_frameIterator) {
        m_cel = layer->cel(*m_frameIterator);
        if (m_cel)
          break;
      }
    }

    if (!m_cel)
      layer = layer->getNextInWholeHierarchy();
  }

  if (m_cel && flags == CelsRange::UNIQUE)
    m_visited.insert(m_cel->data()->id());
}

CelsRange::iterator& CelsRange::iterator::operator++()
{
  if (!m_cel)
    return *this;

  auto endFrame = m_selFrames.end();
  if (m_frameIterator != endFrame)
    ++m_frameIterator;

  Layer* layer = m_cel->layer();
  m_cel = nullptr;
  while (layer && !m_cel) {
    if (layer->isImage()) {
      for (; m_frameIterator != endFrame; ++m_frameIterator) {
        m_cel = layer->cel(*m_frameIterator);
        if (m_cel) {
          if (m_flags == CelsRange::UNIQUE) {
            if (m_visited.find(m_cel->data()->id()) == m_visited.end()) {
              m_visited.insert(m_cel->data()->id());
              break;
            }
            else
              m_cel = nullptr;
          }
          else
            break;
        }
      }
    }

    if (!m_cel) {
      layer = layer->getNextInWholeHierarchy();
      m_frameIterator = m_selFrames.begin();
    }
  }
  return *this;
}

CelList CelsRange::toList()
{
  CelList list;
  int n = size();
  if (n > 0) {
    list.reserve(n);
    for (Cel* cel : *this)
      list.push_back(cel);
  }
  return list;
}

} // namespace doc
