// distributable pairwise
// stuart meikle
// begun Tue Feb 22 10:45:47 2000

// NOTE: an image is just a matrix of 'T' type objects. I'm not going to attempt
// to build in palette information here -> that would be the job of who-ever/whatever
// interprets and renders the image, not a property of the image itself.

// Thu May  4 14:05:13 2000. stu the meikle
// added Iiiiiiiiiiimage Maaaaaagick stuff today. (Its good so you have to say
// like you're introducing it on stage). enables images to be written to file in
// numerous formats.

// Tue Sep 26 13:56:01 - Bala Amavasai
// added readFromFile - read image from file
//                      rawData - pointer to the data - useful for directly thunking data in KLT

// Wed Mar 7 19:06:02 - Bala Amavasai
// ImageMagick functions are all F-ed up since versions from 5.2.9 are 16-bit.
// readFromFile seems okay but writeToFile doesn't want to work
// added    readFromFilePGM - read PGM file
//                         writeToFilePGM  - write PGM to file
// the above two functions require netpbm to be installed - note that some buggy installations
// do not include shopts, in which case compile it 'yerself and install it!

// Sat May  4 14:24:14 2002 - Stu Meikle
// some tidying up. made the destructor virtual, which is more useful for images which
// have pointers at each pixel. (edgel images etc).
// addded a switch for objectID, because it's a big structure! (remember histograms
// are images but often not much bigger than 255 bytes).

// SUGGESTION: keep all QT specific code in the image files only. 
// (in case someone needs to remove / switch it in the future)
//
// $Header: /cvs/mimas2/include/image.h,v 1.3 2005/08/16 20:46:51 engmb Exp $
//

#ifndef IMAGE_H
#define IMAGE_H

#include <boost/multi_array.hpp>
#include <algorithm>
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <string>
#include "image_ref.h"
#include "multi_array_op.h"
#include "mimasexception.h"

namespace mimas {

/** Template class for images.
    Hmmm. Well. image is a generic image class. You specify the pixel type
    at creation time. So if you want an image of ints do
    \code
    image<int> my_image;
    \endcode
    and so on. */
template<typename T>
class image: public image_ref< T >
{
public:
  
  image(void) {}
  
  /// Copy-constructor.
    /* image( const image< T > &_image )
  {
    operator=( _image );
    } */

  template< typename U, typename UPtr >
    image( const const_image_ref< U, UPtr > &_image ) {
    operator=( _image );
  };
  
  virtual void init( int w , int h ) {
    // Only resize, if necessary.
    if ( w != image< T >::width || h != image< T >::height ) {
      storage = boost::shared_array< T >( new T[ w * h ] );
      // pgh requires this
      std::fill( storage.get(), storage.get() + w * h, T() );
      image< T >::width = w;
      image< T >::height = h;
      image< T >::data = storage.get();
    };
  }

  virtual void clear( void ) {
    storage.reset();
    image< T >::width = 0;
    image< T >::height = 0;
    image< T >::data = NULL;
  }

  /*
        !!!!!! the compiler do a segmentation fault on this code. 
      image<T> subImage(const Pixel ul, const Pixel lr) const
      {
        assert(ul.x < getWidth() && lr.x < getWidth()
               && ul.y < getHeight() && lr.y < getHeight());
        typedef typename boost::multi_array<T,2>::index_range range;
        typedef boost::multi_array<T,2>::array_view<2>::type mm_sub_array_t;
        mm_sub_array_t subArray =
          //        rawData()[boost::indices[range(ul.y, lr.y)][range(ul.x, lr.x)]];
          rawData()[boost::indices[range(1, 12)][range(32, 45)]];
        return image<T>(boost::multi_array<T,2>(subArray));
      }
      */
 
  image<T>& operator=( const image<T> &_image )
  {
    image< T >::dummy = T();
    init( _image.getWidth(), _image.getHeight() );
    const T *p = _image.rawData();
    T *q = image< T >::rawData();
    int size = image< T >::width * image< T >::height;
    for ( int i=0; i<size; i++ )
      *q++ = (T)*p++;
    return (*this);
  };
  
  template< typename U, typename UPtr >
  image& operator=( const const_image_ref<U,UPtr> &_image )
  {
    image< T >::dummy = T();
    init( _image.getWidth(), _image.getHeight() );
    const U *p = _image.rawData();
    T *q = image< T >::rawData();
    int size = image< T >::width * image< T >::height;
    for ( int i=0; i<size; i++ )
      *q++ = (T)*p++;
    return (*this);
  };
  
protected:
  /// Storage.
  boost::shared_array< T > storage;
};

}

#endif