// This may look like C code, but it's really -*- C++ -*-
/*
 * Copyright (C) 2008 Emweb bvba, Kessel-Lo, Belgium.
 *
 * See the LICENSE file for terms of use.
 */
#ifndef DATA_STORE_H_
#define DATA_STORE_H_

#include <string>
#include <Wt/WResource>
#include <Wt/Ext/Widget>
#include <Wt/Ext/ExtDllDefs.h>

namespace Wt {

  class WAbstractItemModel;
  class WModelIndex;

  namespace Ext {

/*! \class DataStore Wt/Ext/DataStore Wt/Ext/DataStore
 *  \brief A resource that serializes data from a data model
 *
 * An instance of this class is used by ComboBox and TableView widgets
 * to serialize data from a WAbstractItemModel. The data store can
 * serialize data both for a ClientSide or ServerSide location of the data.
 * When the location is ServerSide, the model supports transmission of
 * certain data pages, and filtering of the model.
 *
 * To use the data store, you need to specify which columns from the model
 * need to be serialized.
 *
 * \ingroup ext
 */
class WT_EXT_API DataStore : public WResource
{
public:
  /*! \brief Create a new data store.
   *
   * Data will be fecthed from <i>model</i>.
   */
  DataStore(WAbstractItemModel *model, DataLocation dataLocation,
	    WObject *parent = 0);

  /*! \brief Destructor.
   */
  ~DataStore();

  /*! \brief Add a column to the list of columns to be serialized.
   *
   * The column <i>columnIndex</i> of the model is added to the current
   * list of columns that are serialized. The <i>jsonName</i> provides the
   * column label that is transmitted.
   */
  void addColumn(int columnIndex, const std::string& jsonName);

  /*! \brief Set the column which is used to handle filter requests.
   *
   * A request for filtering data will be done by matching the given filter
   * against data in the model at column <i>columnIndex</i>.
   */
  void setFilterColumn(int columnIndex);

  std::string jsCreateStore();
  std::string jsCreateRecordDef(const std::string& storeVar) const;

  void setModel(WAbstractItemModel *model);
  void modelRowsInserted(int start, int end);
  void modelRowsRemoved(int start, int end);
  void modelDataChanged(const WModelIndex& topLeft,
			const WModelIndex& bottomRight);

  std::string jsGetUpdates(const std::string& storeVar);

  int rowFromId(int id) const;

  std::string load(const std::string& storeVar, int pageSize);

protected:
  virtual void handleRequest(const Http::Request& request,
			     Http::Response& response);

private:
  WAbstractItemModel *model_;
  DataLocation        dataLocation_;
  std::vector<int>    recordIds_; // -1 indicates new row
  int  nextId_;
  int  modelFilterColumn_;

  struct Column {
    int         modelColumn;
    std::string fieldName;

    Column(int aModelColumn, const std::string& aFieldName);
  };

  std::vector<Column> columns_;

  std::string      jsChanges_;    // changes in existing rows
  std::vector<int> rowsDeleted_;  // rows deleted
  bool             rowsInserted_;
  bool needRefresh_;

  int getRecordId(int row);
  std::string dataAsJSLiteral(int row, int col) const;
};

  }
}

#endif // JSON_DATASTORE_H_
