#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"

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> dbdir("d", "db", "database dirctory", true, "", "databaase");

      TCLAP::ValueArg<std::string> xmlout( "x", "xml", "output xml file", true, "", "xml file");

#ifndef _NOMAGICK_
      Magick::Image mim;
#endif

      cmd.add(dbdir);
      cmd.add(xmlout);

      cmd.parse(argc, argv);

      bdbenv bdb;
      dbimage imstore;
      bdb.open( dbdir.getValue() );
      imstore.init( bdb.envptr() );
      bdb.adddb( &imstore );
      bdb.cleanlog();
      tileimage tileim;
      tile *a, *b;
      std::vector< std::pair<int, int> > alnids;
      std::vector< image2d* > imsa, imsb;
      for( int i = 5; i < 15; i++ )
        {
          std::pair< int, int > ta;
          ta.first = i;
          ta.second = 0;
          alnids.push_back( ta );
          ta.second = 1;
          alnids.push_back( ta );
          ta.second = 2;
          alnids.push_back( ta );
        }
      
      tileim.init( &imstore );
      std::vector< int > mytiles;
      tileim.getsize( mytiles );
      pso mypso;
      for( unsigned i = 0; i < mytiles.size(); i++ )
        {
          for( int j = 1; j < mytiles[i]; j++ )
            {
              std::cout << "aligning " << j-1 << " "
                        << j << "\n";
              a = tileim.gettile(i, j-1);
              b = tileim.gettile(i, j);
              std::cout << "loading tile " << i << " "
                        << j-1 << "\n";
              a->getimages( alnids, imsa );
              std::cout << "loading tile " << i << " "
                        << j << "\n";
              b->getimages( alnids, imsb );
              std::cout << "finished loading\n";
              histequalize heq;
              std::cout << "equalizing...\n";
              for( unsigned k = 0; k < imsa.size(); k++ )
                {
                  heq.init( QUANTIZEFACTOR );
                  heq.addimage( imsa[k] );
                  heq.addimage( imsb[k] );
                  heq.equalize( imsa[k] );
                  heq.equalize( imsb[k] );
                }
              image2d map1, map2;
              map1.load( imsa[0] );
              map2.load( imsb[0] );
              map1.setall( 1 );
              map2.setall( 1 );
              mypso.init( imsa, imsb, map1, map2 );
              timer mytimer;
              mytimer.reset();
              mytimer.start();
              mypso.mpoptimize( 80, -20, 10, 20, 500 );
              mytimer.stop();
              std::cout << "ALIGNMENT FINISHED IN: " << mytimer.getseconds() << "\n";
              std::vector< transformation > trans;
              trans.clear();
              mypso.getresult( trans );
              tileim.setalignments( i, j-1, i, j, trans );
              for( unsigned k = 0; k < imsa.size(); k++ )
                {
                  if( imsa[k] != NULL )
                    delete imsa[k];
                  else
                    std::cout << "ERROR: a " << alnids[k].first << "\n";
                }
              for( unsigned k = 0; k < imsb.size(); k++ )
                {
                  if( imsb[k] != NULL )
                    delete imsb[k];
                  else
                    std::cout << "ERROR: b " << alnids[k].first << "\n";
                }
              imsa.clear();
              imsb.clear();
            }
        }
      std::string myts;
      tileim.outputtrans( myts );
      std::ofstream of;
      std::string fn;
      fn = xmlout.getValue();
      of.open( fn.c_str(), std::ios::out | std::ios::trunc );
      if( of.is_open() )
        of << myts;
      else
        std::cout << myts;
      of.close();
      imstore.close();
      bdb.close();
    }
  catch (TCLAP::ArgException &e)
    {
      std::cout << "ERROR: " << e.error() 
                << " for arg " << e.argId() << "\n";
      return 0;
    }
  return 0;
}
