/***************************************************************************
    copyright            : (C) 2003-2006 by Robby Stephenson
    email                : robby@periapsis.org
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of version 2 of the GNU General Public License as  *
 *   published by the Free Software Foundation;                            *
 *                                                                         *
 ***************************************************************************/

#include "image.h"
#include "imagefactory.h"
#include "tellico_debug.h"
#include "tellico_utils.h"

#include <kmdcodec.h>
#include <kpixmapio.h>
#include <kstaticdeleter.h>

#include <tqbuffer.h>
#include <tqregexp.h>

using Tellico::Data::Image;
using Tellico::Data::ImageInfo;

KPixmapIO* Image::s_pixmapIO = 0;
static KStaticDeleter<KPixmapIO> staticKPixmapIODeleter;
KPixmapIO* Image::io() {
  if(!s_pixmapIO) {
    staticKPixmapIODeleter.setObject(s_pixmapIO, new KPixmapIO());
  }
  return s_pixmapIO;
}

Image::Image() : TQImage(), m_id(TQString()), m_linkOnly(false) {
}

// I'm using the MD5 hash as the id. I consider it rather unlikely that two images in one
// collection could ever have the same hash, and this lets me do a fast comparison of two images
// simply by comparing their ids.
Image::Image(const TQString& filename_) : TQImage(filename_), m_linkOnly(false) {
  m_format = TQImage::imageFormat(filename_);
  calculateID();
}

Image::Image(const TQImage& img_, const TQString& format_) : TQImage(img_), m_format(format_.ascii()), m_linkOnly(false) {
  calculateID();
}

Image::Image(const TQByteArray& data_, const TQString& format_, const TQString& id_)
    : TQImage(data_), m_id(idClean(id_)), m_format(format_.ascii()), m_linkOnly(false) {
  if(isNull()) {
    m_id = TQString();
  }
}

Image::~Image() {
}

TQByteArray Image::byteArray() const {
  return byteArray(*this, outputFormat(m_format));
}

bool Image::isNull() const {
  // 1x1 images are considered null for Tellico. Amazon returns some like that.
  return TQImage::isNull() || (width() < 2 && height() < 2);
}

TQPixmap Image::convertToPixmap() const {
  return io()->convertToPixmap(*this);
}

TQPixmap Image::convertToPixmap(int w_, int h_) const {
  if(w_ < width() || h_ < height()) {
    return io()->convertToPixmap(this->smoothScale(w_, h_, ScaleMin));
  } else {
    return io()->convertToPixmap(*this);
  }
}

TQCString Image::outputFormat(const TQCString& inputFormat) {
  TQStrList list = TQImage::outputFormats();
  for(TQStrListIterator it(list); it.current(); ++it) {
    if(inputFormat == it.current()) {
      return inputFormat;
    }
  }
//  myDebug() << "Image::outputFormat() - writing " << inputFormat << " as PNG" << endl;
  return "PNG";
}

TQByteArray Image::byteArray(const TQImage& img_, const TQCString& outputFormat_) {
  TQByteArray ba;
  TQBuffer buf(ba);
  buf.open(IO_WriteOnly);
  TQImageIO iio(&buf, outputFormat_);
  iio.setImage(img_);
  iio.write();
  buf.close();
  return ba;
}

TQString Image::idClean(const TQString& id_) {
  static const TQRegExp rx('[' + TQRegExp::escape(TQString::fromLatin1("/@<>#\"&%?={}|^~[]'`\\:+")) + ']');
  TQString clean = id_;
  return shareString(clean.remove(rx));
}

void Image::setID(const TQString& id_) {
  m_id = id_;
}

void Image::calculateID() {
  // the id will eventually be used as a filename
  if(!isNull()) {
    KMD5 md5(byteArray());
    m_id = TQString::fromLatin1(md5.hexDigest()) + TQString::fromLatin1(".") + TQString::fromLatin1(m_format).lower();
    m_id = idClean(m_id);
  }
}

/******************************************************/

ImageInfo::ImageInfo(const Image& img_)
    : id(img_.id())
    , format(img_.format())
    , linkOnly(img_.linkOnly())
    , m_width(img_.width())
    , m_height(img_.height()) {
}

ImageInfo::ImageInfo(const TQString& id_, const TQCString& format_, int w_, int h_, bool l_)
    : id(id_)
    , format(format_)
    , linkOnly(l_)
    , m_width(w_)
    , m_height(h_) {
}

int ImageInfo::width(bool loadIfNecessary) const {
  if(m_width < 1 && loadIfNecessary) {
    const Image& img = ImageFactory::imageById(id);
    if(!img.isNull()) {
      m_width = img.width();
      m_height = img.height();
    }
  }
  return m_width;
}

int ImageInfo::height(bool loadIfNecessary) const {
  if(m_height < 1 && loadIfNecessary) {
    const Image& img = ImageFactory::imageById(id);
    if(!img.isNull()) {
      m_width = img.width();
      m_height = img.height();
    }
  }
  return m_height;
}
