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

#ifndef DOC_TILESETS_H_INCLUDED
#define DOC_TILESETS_H_INCLUDED
#pragma once

#include "doc/layer_tilemap.h"
#include "doc/sprite.h"
#include "doc/tileset.h"

#include <vector>

namespace doc {

  class Tilesets : public Object {
  public:
    typedef std::vector<Tileset*> Array;
    typedef Array::iterator iterator;
    typedef Array::const_iterator const_iterator;

    Tilesets();
    ~Tilesets();

    int getMemSize() const override;

    iterator begin() { return m_tilesets.begin(); }
    iterator end() { return m_tilesets.end(); }
    const_iterator begin() const { return m_tilesets.begin(); }
    const_iterator end() const { return m_tilesets.end(); }
    tileset_index size() const { return (tileset_index)m_tilesets.size(); }

    tileset_index add(Tileset* tileset);

    Tileset* get(const tileset_index tsi) const {
      if (tsi < size())
        return m_tilesets[tsi];
      return nullptr;
    }

    tileset_index getIndex(const Tileset *tileset) {
      for (tileset_index i = 0; i < size(); ++i) {
        if (m_tilesets[i] == tileset) {
          return i;
        }
      }
      return -1;
    }

    void set(const tileset_index tsi, Tileset* tileset) {
      if (tsi >= m_tilesets.size())
        m_tilesets.resize(tsi+1, nullptr);
      m_tilesets[tsi] = tileset;
    }

    void add(const tileset_index tsi, Tileset* tileset) {
      if (tsi >= m_tilesets.size()) {
        m_tilesets.push_back(tileset);
      }
      else {
        m_tilesets.insert(m_tilesets.begin()+tsi, tileset);
        // Update tileset indexes of the affected tilemaps. We have to shift the indexes
        // for all the tilemaps pointing to a tileset index equals or greater than the added one.
        shiftTilesetIndexes(tileset->sprite(), tsi, 1);
      }
    }

    void erase(const tileset_index tsi) {
      // When tsi is the last one, other tilemaps tilesets
      // indexes are not affected.
      if (tsi == size()-1) {
        m_tilesets.erase(--m_tilesets.end());
      }
      else {
        auto ts = m_tilesets[tsi];
        m_tilesets.erase(m_tilesets.begin()+tsi);
        // Update tileset indexes of the affected tilemaps. We have to shift the indexes
        // for all the tilemaps pointing to a tileset index greater than the deleted one.
        shiftTilesetIndexes(ts->sprite(), tsi+1, -1);
      }
    }

  private:
    Array m_tilesets;

    void shiftTilesetIndexes(Sprite *sprite, tileset_index pos, int n) {
      for (auto layer : sprite->allTilemaps()) {
        auto tilemap = static_cast<LayerTilemap*>(layer);
        if (tilemap->tilesetIndex() >= pos) {
          tilemap->setTilesetIndex(tilemap->tilesetIndex()+n);
        }
      }
    }
  };

} // namespace doc

#endif
