#ifndef __PSOTRACKER_H__
#define __PSOTRACKER_H__
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <vector>
#include <iostream>
#include <list>
#include <math.h>
#include "image2d.h"
#include "bdbenv.h"
#include "psoparticle.h"
#include "transcache.h"
#include "timer.h"
#include "emcluster.h"
#include "gaussianmodel.h"

struct psotrack_slice
{
  int psoslice;
  int dbslice;
  int dbtilex1;
  int dbtiley1;
  int dbalignedtile1;
  int dbtilex2;
  int dbtiley2;
  int dbalignedtile2;
  int dbchannel;
};

struct psotrack_cluster
{
  double x;
  double y;
};

struct psotrack_cachestat
{
  int psoslice;
  int size;
  double hit;
};

class psotracker
{
 public:
  psotracker();
  ~psotracker();
  int upgrade( std::string dbfile );
  int init( std::string dbfile, int rebildindex = 0 );
  int close();
  int set_runconfig( std::vector< psotrack_slice > &psoslicedata, 
                     int parperslice,
                     box searchbox );
  int save_iterationdata( int iteration, std::vector< psoparticle* > &pvec,
                          std::vector< psotrack_cluster > &kmeans, 
                          std::vector< psotrack_cachestat > &cache,
                          std::vector< transformation > *newtrans );

  /// return percentage of search space actually searched
  double searched();

  /// prints two images containing the avage and std mutual information score
  int printavgmiscore();

  /// prints the amount of overlap in the search space
  int printsearched();

  /// gets a list of pso particles for a slice at a iteration
  int getparticles( int iteration, int psoslice, 
                    std::vector< psoparticle > &particles );

  /// gets a list of pso particles at a iteration
  int getparticles( int iteration,
                    std::vector< psoparticle > &particles );

  int printpoints( int iteration );

  int printsliceparticles( int iteration );

  int printsliceparticles( double &lowx, double &lowy,
                           double &highx, double &highy);

  struct slice_setup_value
  {
    int slice;
    int dbtx1;
    int dbty1;
    int dba1;
    int dbtx2;
    int dbty2;
    int dba2;
    int channel;
  };

  struct trans_cache_key
  {
    int iteration;
    int psoslice;
  };
  struct trans_cache_value
  {
    int size;
    double hit;
  };
  struct mi_score_key
  {
    int slice;
    int x;
    int y;
  };
  struct cluster_table_key
  {
    int iteration;
    int cid;
  };
  struct cluster_table_value
  {
    double x;
    double y;
  };
  struct particle_state_key
  {
    int iteration;
    int pid;
  };
  struct particle_state_value
  {
    double x;
    double y;
    double vx;
    double vy;
    double speed;
  };
  struct particle_setup_value
  {
    int psoslice;   ///< slice number in pso image stack
    int parslice;   ///< particle number in slice
  };

 private:

  double getparam( std::string name );

  int avgstd( std::vector< double > &vlist,
              double &avg, double &std );

  int setparam( std::string name, double val );

  int save_cache( int iteration,  psotrack_cachestat &cs );
  int save_kmeans( int iteration, int cid, psotrack_cluster &c );
  int save_pso_particles( int iteration, psoparticle *p );
  int savemutualinformation( transformation &t, int slice );
  int droptables();
  int createtables();
#ifndef _NOMAGICK_
  int overlaygrid( Magick::Image &mim );
#endif
  int clusterparticles( std::list< particle_state_value > &lpsv,
                        std::vector< gaussianmodel* > &gms);

#ifndef _NOMAGICK_
  int overlaygaussians( Magick::Image &mim,
                        std::vector< gaussianmodel* > gms );
#endif

  int closestgaussian( double x, double y,
                       std::vector< gaussianmodel* > &gsm );

#ifndef _NOMAGICK_
  int generatecolors( std::vector< Magick::ColorRGB > &colors,
                      int ncolors );
#endif

  /// filter particles by iteration and speed
  int filterparticles( int iteration, double speed,
                       std::list< particle_state_value > &plist );
  
  /// filter outliers by radius
  int filteroutliers( int radius,
                      std::list< particle_state_value > &plist );

  std::string dbfilename;
  int myparperslice;
  int myslices;
  bdbenv bdb;
  Db *pso_paramdb;
  Db *slice_setupdb;

  Db *trans_cachedb;        ///< db for storing cache
  Db *trans_cache_iteridx;
  Db *trans_cache_sliceidx;
  Db *trans_cache_sizeidx;
  Db *trans_cache_hitidx;

  Db *mi_scoredb;
  Db *mi_score_sliceidx;
  Db *mi_score_xyidx;
  Db *mi_score_scoreidx;

  Db *particle_setupdb;
  Db *particle_setup_psosliceidx;

  Db *particle_statedb;
  Db *particle_state_vxidx;
  Db *particle_state_vyidx;
  Db *particle_state_speedidx;
  Db *particle_state_iteridx;
  Db *particle_state_pididx;

  Db *iteration_statdb;

  Db *cluster_positiondb;
  DbTxn *mytxn;
};

#endif
