#pragma once
/*
    File: iterator.h
*/

/*
Copyright (c) 2014, Christian E. Schafmeister

CLASP is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.

See directory 'clasp/licenses' for full details.

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/* -^- */

#include <stdio.h>
#include <string>
#include <vector>
#include <set>
#include <clasp/core/object.h>

namespace core {

SMART(Iterator);
class Iterator_O : public General_O {
  LISP_ABSTRACT_CLASS(core, CorePkg, Iterator_O, "Iterator", General_O);

public:
  // Untagged C++ subclasses (e.g. clbind::Iterator<X>) don't have their own
  // LISP_CLASS-generated __class() override.  Without this, virtual dispatch
  // walks past us to General_O::__class() and instances report General_O as
  // their class — breaking single-dispatch on iterator= and similar.
  virtual core::Instance_sp __class() const override {
    return core::lisp_getStaticClass(Iterator_O::static_ValueStampWtagMtag);
  }

  void initialize() override;

private:
public:
  // New way of doing things

  virtual T_sp unsafeElement() const { SUBIMP(); }; // if you dereference the end of the sequence - BAD THINGS WILL HAPPEN
  virtual void step() { SUBIMP(); };
  virtual bool operator==(T_sp other) const { SUBIMP(); };
  virtual bool operator<(T_sp other) const { SUBIMP(); };
  virtual bool eql_(T_sp other) const override { return this->operator==(other); };
  virtual size_t templatedSizeof() const override { SUBIMP(); };

  // Old way of doing things
  CL_LISPIFY_NAME("core:begin");
  CL_DEFMETHOD virtual void first() {
    _OF();
    SUBCLASS_MUST_IMPLEMENT();
  };
  CL_LISPIFY_NAME("next");
  CL_DEFMETHOD virtual void next() {
    _OF();
    SUBCLASS_MUST_IMPLEMENT();
  };

  CL_LISPIFY_NAME("iterator_EQ_");
  CL_DEFMETHOD virtual bool iterator_EQ_(core::T_sp other) { return this->operator==(other); };
  size_t iterator_distance(core::T_sp other);

  CL_LISPIFY_NAME("isDone");
  CL_DEFMETHOD virtual bool isDone() {
    _OF();
    SUBCLASS_MUST_IMPLEMENT();
  };
  CL_LISPIFY_NAME("notDone");
  CL_DEFMETHOD virtual bool notDone() { return !this->isDone(); };
  CL_LISPIFY_NAME("currentObject");
  CL_DEFMETHOD virtual T_sp currentObject() {
    _OF();
    SUBCLASS_MUST_IMPLEMENT();
  };
  template <typename OType> gctools::smart_ptr<OType> current() {
    return gctools::As<gctools::smart_ptr<OType>>(this->currentObject());
  };

  //	Iterator_O( const Iterator_O& ss ); //!< Copy constructor

  DEFAULT_CTOR_DTOR(Iterator_O);
};
}; // namespace core
