#ifndef _NOMAGICK_
#include <Magick++.h>
#endif

#include <iostream>
#include <string>
#include <fstream>
#include <math.h>
#include "imagealign.h"
#include "image2d.h"
#include <fftw3.h>
#include <tclap/CmdLine.h>
#include "bdbenv.h"
#include "dbimage.h"
#include "pso.h"
#include "histequalize.h"
#include "tile.h"
#include "tileimage.h"
#include "alignimage.h"
#include "dbtmpfeature.h"
#include "som.h"
#include "texturefeature.h"
#include <algorithm>
#include <sys/types.h>
#include <dirent.h>
#include "object.h"

int getimages( std::string dir,
               std::vector< std::string > &files );
int filterimages( som &mysom, std::string dir,
                  std::vector<std::string> &flist );
int process( som &mysom, std::string file,
             std::map<int, int> &scount,
             object &obj, int phase);

int getimages( std::string dir, 
               std::vector< std::string > &files )
{
  DIR *dp;
  struct dirent *dirp;
  dp = opendir( dir.c_str() );
  if( dp == NULL )
    return -1;
  dirp = readdir( dp );
  while( dirp != NULL )
    {
      if( strncmp( "class", dirp->d_name, 5 ) == 0 &&
          strstr( dirp->d_name, ".tif" ) != NULL )
        {
          std::cout << "found " << dirp->d_name << "\n";
          files.push_back( std::string(dirp->d_name) );
        }
      dirp = readdir(dp);
    }
  closedir( dp );
  return 0;
}

int filterimages( som &mysom, std::string dir,
                  std::vector<std::string> &flist )
{
  object obj;
  std::map< int, int > count;
  for( unsigned int i = 0; i < flist.size(); i++ )
    process( mysom, dir+"/"+flist[i], count, obj, 0 );
  std::cout << "total size: " << obj.size() << "\n";
  obj.errode();
  obj.expand();
  std::cout << "final size: " << obj.size() << "\n";
  obj.xmlprint( "object.xml" );
  for( unsigned int i = 0; i < flist.size(); i++ )
    process( mysom, dir+"/"+flist[i], count, obj, 1 );

  for( std::map<int, int>::iterator it = count.begin();
       it != count.end(); it++ )
    std::cout << it->first << "->" << it->second << "\n";
  return 0;
}

int process( som &mysom, std::string file,
             std::map<int, int> &scount,
             object &myobj, int phase )
{
  int width, height;
  Magick::Image mim;
  mim.read( file.c_str() );

  int id;
  for( unsigned int z = 0; z < file.size(); z++ )
    {
      if( ((int)file[z]) < 48 ||
          ((int)file[z]) > 57 )
        file[z] = ' ';
    }
  std::cout << "'" << file << "'\n";
  id = strtol( file.c_str(), NULL, 10 );

  Magick::Geometry geo = mim.size();
  width = geo.width();
  height = geo.height();
  Magick::PixelPacket *pixel_cache
    = mim.getPixels(0,0,width,height);
  Magick::ColorRGB rgb;
  std::vector< int > coor, dims;
  coor.resize(3);
  std::cout << "processing " << file << "\n"
            << std::flush;
  mysom.getsomsize( dims );
  int count = 0;
  for(int i = 0; i < height; i++)
    {
      for(int j = 0; j < width; j++)
	{
          rgb = pixel_cache[i*width+j];
          coor[0] = round(rgb.red()*dims[0])-1;
          coor[1] = round(rgb.green()*dims[1])-1;
          coor[2] = round(rgb.blue()*dims[2])-1;
          int f;
          f = 0;
          if( phase == 0 )
            {
              if( coor[0] >= 0 )
                f = mysom.checkspecial( coor );
              if( f != 1 )
                {
                  rgb.red(0);
                  rgb.green(0);
                  rgb.blue(0);
                  pixel_cache[i*width+j] = rgb;
                }
              else
                {
                  myobj.addpixel( i, j, id );
                  count++;
                }
            }
          else
            {
              if( myobj.count(i,j,id) == 0 )
                {
                  rgb.red(0);
                  rgb.green(0);
                  rgb.blue(0);
                  pixel_cache[i*width+j] = rgb;
                }
              else
                count++;
            }
        }
      if( i % 64 == 0 )
        std::cout << "." << std::flush;
    }
  std::cout << "\n";

  scount[id] = count;
  mim.syncPixels();
  if( phase == 1 )
    {
      char buffer[128];
      sprintf( buffer, "filtered%i.png", id );
      mim.write( buffer );
    }
  return 0;
}

int main( int argc, char *argv[] )
{
  try
    {
      ///set up the command line parsing
      TCLAP::CmdLine cmd("Image alignment program", ' ', "0.001");

      TCLAP::ValueArg<std::string> imagedir( "i", "images", "image directory", true, ".", "directory");
      TCLAP::ValueArg<std::string> somxml( "x", "xml", "xml som file", true, "", "xml");

      cmd.add( somxml );
      cmd.add( imagedir );

      cmd.parse(argc, argv);

      som mysom;

      mysom.init( NULL, somxml.getValue() );
      std::vector< std::string > imagelist;
      getimages( imagedir.getValue(), imagelist );
      
      filterimages( mysom, imagedir.getValue(),
                    imagelist );

    }
  catch (TCLAP::ArgException &e)
    {
      std::cout << "ERROR: " << e.error() 
                << " for arg " << e.argId() << "\n";
      return 0;
    }
  return 0;
}
