/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
 * This file is part of the libepubgen project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include <cassert>
#include <iomanip>
#include <sstream>

#include <boost/assign/list_of.hpp>

#include "EPUBBinarySink.h"
#include "EPUBImageManager.h"
#include "EPUBManifest.h"

namespace libepubgen
{

using librevenge::RVNGBinaryData;

using std::string;

namespace
{

string getExtension(const string &mimetype)
{
  typedef boost::unordered_map<string, string> Map_t;

  static Map_t extensionMap = boost::assign::map_list_of<string, string>
                              ("image/gif", "gif")
                              ("image/jpeg", "jpg")
                              ("image/png", "png")
                              ("image/svg+xml", "svg")
                              ;

  Map_t::const_iterator it = extensionMap.find(mimetype);
  return (extensionMap.end() == it) ? string("img") : it->second;
}

}

std::size_t EPUBImageManager::BinaryDataHash::operator()(const librevenge::RVNGBinaryData &data) const
{
  size_t seed = 0;

  const unsigned char *const buf = data.getDataBuffer();
  for (size_t i = 0; data.size() != i; ++i)
    boost::hash_combine(seed, buf[i]);

  return seed;
}

bool EPUBImageManager::BinaryDataEqual::operator()(const librevenge::RVNGBinaryData &left, const librevenge::RVNGBinaryData right) const
{
  if (left.empty() && right.empty())
    return true;
  if (left.size() != right.size())
    return false;
  const unsigned char *const leftData = left.getDataBuffer();
  return std::equal(leftData, leftData + left.size(), right.getDataBuffer());
}

EPUBImageManager::EPUBImageManager(EPUBManifest &manifest)
  : m_manifest(manifest)
  , m_map()
  , m_number()
{
}

const EPUBPath &EPUBImageManager::insert(const librevenge::RVNGBinaryData &data, const librevenge::RVNGString &mimetype)
{
  MapType_t::const_iterator it = m_map.find(data);
  if (m_map.end() == it)
  {
    const string mime(mimetype.cstr());

    std::ostringstream nameBuf;
    nameBuf << "image" << std::setw(4) << std::setfill('0') << m_number.next();
    const string id = nameBuf.str();

    nameBuf << "." << getExtension(mime);

    const EPUBPath path(EPUBPath("OEBPS/images") / nameBuf.str());

    m_manifest.insert(path, mime, id);
    it = m_map.insert(MapType_t::value_type(data, path)).first;
  }

  assert(m_map.end() != it); // the image must be present at this point

  return it->second;
}

void EPUBImageManager::writeTo(EPUBPackage &package)
{
  for (MapType_t::const_iterator it = m_map.begin(); m_map.end() != it; ++it)
  {
    EPUBBinarySink sink;
    sink.insertBinaryData(it->first);
    sink.writeTo(package, it->second.str().c_str());
  }
}

}

/* vim:set shiftwidth=2 softtabstop=2 expandtab: */
