#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 "expat.h"

int calchistogram( histequalize *myhist, image2d *mymask, int aid,
                   std::set<int> *sl, int mych, dbalnimage *adb );
int printslices( histequalize *myhist, int aid, std::set<int> *sl, 
                 int mych, dbalnimage *adb, const char *wdir );

int composite( image2d &myimr, image2d &myimb, Magick::Image &mim );

int composite( image2d &myimr, image2d &myimb, Magick::Image &mim )
{
  int width, height;
  width = myimr.getwidth();
  height = myimr.getheight();
  Magick::Geometry geo;
  geo.width(width);
  geo.height(height);
  mim.type( Magick::TrueColorType );
  mim.size( geo );
  Magick::ColorRGB rgb(0, 0, 0);
  Magick::PixelPacket *pixel_cache = mim.getPixels(0,0,width,height);
  for(int i = 0; i < height; i++)
    {
      for(int j = 0; j < width; j++)
	{
	  rgb.isValid(true);
          double rv, bv;
          rv = myimr.getpixel(i,j);
          bv = myimb.getpixel(i,j);
          rv = rv * (1-bv);
          rgb.red( rv );
	  rgb.blue( bv );
	  pixel_cache[i*width+j] = rgb;
        }
    }
  mim.syncPixels();
  return 0;
}

int calchistogram( histequalize *myhist, image2d *mymask, int aid,
                   std::set<int> *sl, int mych, dbalnimage *adb )
{
  image2d myim;
  for( std::set<int>::iterator it = sl->begin(); it != sl->end(); it++ )
    {
      adb->get_aligned_image( aid, *it, mych, &myim );
      std::cout << *it << " " << myim.getheight() << "x" 
                << myim.getwidth() << "\n";
      myim.median( 2 );
      myhist->addimage( &myim, mymask );
    }
  return 0;
}

int printslices( histequalize *myhistr, histequalize *myhistb, int aid, std::set<int> *sl,
                 int mychr, int mychb, dbalnimage *adb, const char *wdir )
{
#ifndef _NOMAGICK_
  image2d myimr, myimb;
  Magick::Image mim;
  char *fn;
  char *mycwd;
  int mycwdlen;
  mycwdlen = 256;
  fn = new char[256];
  mycwd = new char[mycwdlen];
  char *ret;
  ret = getcwd( mycwd, mycwdlen );
  while( ret == NULL )
    {
      delete [] mycwd;
      mycwdlen= mycwdlen*2;
      if( mycwdlen > 1024*1024 )
        {
          delete [] fn;
          std::cout << "ERROR current directory name too long\n";
          return 0;
        }
      mycwd = new char[mycwdlen];
    }
  if( chdir( wdir ) != 0 )
    {
      delete [] mycwd;
      delete [] fn;
      std::cout << "ERROR moving to working directory\n";
      return 0;
    }
  for( std::set<int>::iterator it = sl->begin(); it != sl->end(); it++ )
    {
      adb->get_aligned_image( aid, *it, mychr, &myimr );
      //myimr.median( 2 );
      //myhistr->equalize( &myimr );
      myimr.normalize( 0, 256.0/4096.0 );
      adb->get_aligned_image( aid, *it, mychb, &myimb );
      //      myimb.median( 2 );
      //      myhistb->equalize( &myimb );

      myimb.normalize( 0, 256.0/4096.0 );

      composite( myimr, myimb, mim );

      sprintf( fn, "%i-%i_%i_%02i.png", mychr, mychb, aid, *it );
      mim.write( fn );
    }
  if( chdir( mycwd ) != 0 )
    {
      std::cout << "ERROR moving back to original directory\n";
      delete [] mycwd;
      delete [] fn;
      return -1;
    }
  delete [] fn;
  delete [] mycwd;
#endif
  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> dbdir("d", "db", "database dirctory", true, "", "databaase");

      TCLAP::ValueArg<int> aid("a", "aid", "aligned image id", true, 0, "aligned image id");
      TCLAP::ValueArg<int> channelr("r", "redchannel", "red channel to get", true, 0, "channel" );
      TCLAP::ValueArg<int> channelb("b", "bluechannel", "blue channel to get", true, 0, "channel" );

      TCLAP::ValueArg<std::string> dbwork( "w", "work", "working directory", true, "", "working" );

#ifndef _NOMAGICK_
      Magick::Image mim;
#endif

      cmd.add(dbdir);
      cmd.add(aid);
      cmd.add(channelb);
      cmd.add(channelr);
      cmd.add(dbwork);

      cmd.parse(argc, argv);

      bdbenv bdb;
      dbimage imstore;
      dbalnimage dba;

      bdb.open( dbdir.getValue() );
      imstore.init( bdb.envptr() );
      dba.init( bdb.envptr() );
      bdb.adddb( &imstore );
      bdb.adddb( &dba );
      bdb.cleanlog();
      
      int myaid;
      std::cout << "checking aid\n";
      myaid = aid.getValue();
      //check for valid id
      if( dba.checkaid( myaid ) == 1 )
        {
          std::set<int> sl, ch;
          std::cout << "getting slices\n";
          dba.get_slices(myaid, sl );
          std::cout << "getting channels\n";
          dba.get_channels(myaid, ch );
          std::cout << "checking for valid channel\n";
          int mychr, mychb;
          mychr = channelr.getValue();
          mychb = channelb.getValue();
          image2d mymask;
          if( ch.count( mychr ) > 0 && ch.count(mychb) > 0 )
            {
              histequalize myhistr, myhistb;
              myhistr.init( QUANTIZEFACTOR );
              myhistb.init( QUANTIZEFACTOR );
              std::cout << "getting mask\n";
              dba.get_aligned_mask( myaid, &mymask );
              std::cout << "calculating histogram\n";
              //calchistogram( &myhistr, &mymask, myaid, &sl, mychr, &dba );
              //calchistogram( &myhistb, &mymask, myaid, &sl, mychb, &dba );
              std::string wdir;
              wdir = dbwork.getValue();
              std::cout << "printing images\n";
              printslices( &myhistr, &myhistb, myaid, &sl, mychr, mychb, &dba, wdir.c_str() );
            }
          else
            {
              std::cout << "invalid channel\n";
            }
        }
      else
        {
          std::cout << "invalid aid\n";
        }


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