/*------------------------------------------------------------------------------
 src/lib/djImage/image.cxx
 
 Copyright (c) 2004-2006 Darby Johnston.
 All rights reserved.
 Use is subject to license terms.
------------------------------------------------------------------------------*/

#include "djImage.h"
#include <djMath.h>

namespace dj {

Image::Image(const Image & in) :
  PixelData(in),
  _proxy(in._proxy),
  _tagList(in._tagList)
{}

Image::Image() :
  _proxy(0)
{}

Image::Image(const PixelDataInfo & in) :
  PixelData(in),
  _proxy(0)
{}

Image::Image(const Vec2i & size, const Pixel & pixel) :
  PixelData(size, pixel),
  _proxy(0)
{}

bool Image::pixel(const Color & in, const Vec2i & position)
{
  if (position.x() < 0 || position.x() >= width()) return false;
  if (position.y() < 0 || position.y() >= height()) return false;
  pixelCopy(in.data(), data(position), 1, in.pixel(), pixel());
  return true;
}

bool Image::pixel(const Color & in, int x, int y)
{
  if (x < 0 || x >= width()) return false;
  if (y < 0 || y >= height()) return false;
  pixelCopy(in.data(), data(x, y), 1, in.pixel(), pixel());
  return true;
}

void Image::pixel(
  const Vec2i & position, Color * out, EDGE edgeX, EDGE edgeY
) const {
  DJ_ASSERT(out);
  const Vec2i tmp(
    imageEdge(position.x(), width(), edgeX),
    imageEdge(position.y(), height(), edgeY)
  );
  if (-1 == tmp.x() || -1 == tmp.y()) return;
  pixelCopy(data(tmp), out->data(), 1, pixel(), out->pixel());
}

void Image::pixel(
  int x, int y, Color * out, EDGE edgeX, EDGE edgeY
) const {
  DJ_ASSERT(out);
  const int _x = imageEdge(x, width(), edgeX);
  const int _y = imageEdge(y, height(), edgeY);
  if (-1 == _x || -1 == _y) return;
  pixelCopy(data(_x, _y), out->data(), 1, pixel(), out->pixel());
}

void Image::tagList(const ImageTagList & in)
{
  _tagList = in;
}

void Image::proxy(int in)
{
  _proxy = in;
}

int imageEdge(int in, int size, Image::EDGE edge)
{
  int out = -1;
  const int size1 = size - 1;
  switch (edge) {
    case Image::EDGE_CLIP: if (in >= 0 && in <= size1) out = in; break;
    case Image::EDGE_CLAMP: out = clamp(in, 0, size1); break;
    case Image::EDGE_MIRROR:
      if (! size1) out = 0;
      else if (in > size1) out = size1 - mod(in, size1);
      else if (in < 0) out = mod(-in, size1);
      else out = in;
      break;
  }
  return out;
}

int imageProxyScale(int proxy)
{
  return (proxy > 0) ? pow(2, proxy) : 1;
}

const Str keyCodeToStr(int id, int type, int prefix, int count, int offset)
{
  return Str("%1:%2:%3:%4:%5").
    arg(id).arg(type).arg(prefix).arg(count).arg(offset);
}

bool strToKeyCode(
  const Str & in,
  int * id, int * type, int * prefix, int * count, int * offset
) {
  const StrList tmp = split(in, ':');
  if (tmp.size() != 5) return false;
  
  *id = toInt(tmp[0]);
  *type = toInt(tmp[1]);
  *prefix = toInt(tmp[2]);
  *count = toInt(tmp[3]);
  *offset = toInt(tmp[4]);
  
  return true;
}

const Str timeCodeToStr(uint32_t in)
{
  char out [] = "00:00:00:00";

  // Hours, minutes, seconds, frames.
  //
  out[ 0] += in >> 28 & 0x03;
  out[ 1] += in >> 24 & 0x0f;
  out[ 3] += in >> 20 & 0x03;
  out[ 4] += in >> 16 & 0x0f;
  out[ 6] += in >> 12 & 0x07;
  out[ 7] += in >>  8 & 0x0f;
  out[ 9] += in >>  4 & 0x03;
  out[10] += in >>  0 & 0x0f;

  return out;
}

uint32_t strToTimeCode(const Str & in)
{
  char str [] = "00:00:00:00";
  memCopy(in.toAscii(), str, min(in.size(), 11));
  
  return
    ((str[ 0] - '0') & 0x03) << 28 |
    ((str[ 1] - '0') & 0x0f) << 24 |
    ((str[ 3] - '0') & 0x03) << 20 |
    ((str[ 4] - '0') & 0x0f) << 16 |
    ((str[ 6] - '0') & 0x07) << 12 |
    ((str[ 7] - '0') & 0x0f) <<  8 |
    ((str[ 9] - '0') & 0x03) <<  4 |
    ((str[10] - '0') & 0x0f) <<  0;
}

Dbg & operator << (Dbg & dbg, Image::EDGE in)
{
  return dbg << imageEdgeStr()[in];
}

Dbg & operator << (Dbg & dbg, const Image & in)
{
  return dbg << in.size() << " " << in.format() << " " << in.type();
}

}
