/* Copyright 2002 Daniel Egnor.  See LICENSE file.
 *
 * These classes are the interface to query document indexes build. */

#ifndef GEOCODER_IDX_H
#define GEOCODER_IDX_H

extern "C" {
#include "io.h"
}

#include <vector>
#include <string>
#include <stdlib.h>

/* Abstract base class for a sequence of documents. */
class Cursor {
 public:
  Cursor() { }
  virtual ~Cursor() { }
  virtual int Get(int at_least) = 0;
 private:
  void operator=(const Cursor &) { abort(); }
  Cursor(const Cursor &) { abort(); }
};

/* A Cursor built from a specific "zone" in the index.  Used internally;
 * clients shouldn't have to create one of these. */
class ZoneCursor: public Cursor {
 public:
  ZoneCursor(io_file *index, std::pair<int, int> zone)
    : index_(index),
      pos_(zone.first),
      end_(zone.second) {
  }

  int Get(int at_least);

 private:
  io_file * const index_;
  int pos_;
  const int end_;
};

/* A cursor which returns the intersection of the cursors passed to it. */
class AndCursor: public Cursor {
 public:
  template <typename I>
  AndCursor(I begin, I end) : terms_(begin, end) { }
  int Get(int at_least);

 private:
  const std::vector<Cursor *> terms_;
};

/* A cursor which returns the union of the cursors passed to iit. */
class OrCursor: public Cursor {
 public:
  template <typename I>
  OrCursor(I begin, I end) : terms_(begin, end) { }
  int Get(int at_least);

 private:
  const std::vector<Cursor *> terms_;
};

/* A cursor which returns all documents matching a given keyword. */
class TermCursor: public Cursor {
 public:
  TermCursor(io_file *index, const char t[]);
  ~TermCursor();
  int Get(int at_least);

 private:
  io_file * const index_;
  Cursor *term_;
  Cursor *Find(int begin, int end, const char t[]);
};

/* A cursor which returns all documents which contain an address within
 * the given radius of the given location. */
class GeoCursor: public Cursor {
 public:
  GeoCursor(io_file *index, double longitude, double latitude, double radius);
  ~GeoCursor();
  int Get(int at_least);

 private:
  io_file * const index_;
  const double latitude_, longitude_;
  const double radius_;
  std::vector<Cursor *> regions_;
  Cursor *approx_;

  Cursor *Find(int begin, int end, signed char exponent, int east, int north);
};

/* An address found in the index.  Not usually constructed directly, but
 * rather returned from Document's operator[]. */
class Location {
 public:
  Location(io_file *index, int loc);
  std::string Address() const;
  double Longitude() const { return long_ / 1000000.0; }
  double Latitude() const { return lat_ / 1000000.0; }
  bool operator<(const Location &l) const { return begin_ < l.begin_; }

 private:
  io_file * index_;
  int long_, lat_;
  int begin_, end_;
};

/* A document found in the index.  Constructed with the document ID returned
 * from a cursor object. */
class Document {
 public:
  Document(io_file *index, int doc);
  std::string URL() const;
  std::string Title() const;
  bool operator<(const Document &d) const { return u_begin_ < d.u_begin_; }

  /* Number of addresses associated with the document */
  int size() const { return (l_end_ - l_begin_) / l_size_; }

  /* Get an address; the argument should be 0 <= i < size() */
  Location operator[](int) const;

 private:
  static const int l_size_ = 12;

  io_file * index_;
  int l_begin_, l_end_, u_begin_, u_end_;
  mutable std::string url_, title_;

  void GetName() const;
};

#endif

