#pragma once

#include <daguerre/general.hpp>

namespace daguerre {

  //forward declare since these depend on each other
  template <class color_t>
  class fixed_font;

  template <class color_t>
  class image {

  public:
    bool delete_buffer_on_destruct;
    int width;
    int height;
    color_t *buffer;
    int buffer_pitch;//in sizeof(color_t)

    //makes empty image
    image();

    //make image with specified dimensions, contents uninitialized
    image(int width, int height);

    //make image with specified dimensions and buffer
    image(
      int width, int height, color_t *buffer,
      int buffer_pitch, bool delete_buffer_on_destruct);

    //moves the other image's data here, and
    //then sets the other image to an empty one.
    image(image<color_t> &&other);

    //moves the other image's data here, and
    //then sets the other image to an empty one.
    image<color_t> &operator =(image<color_t> &&other);

    //use one of the two constructors below instead
    image(const image<color_t> &other) = delete;

    //copies the other image's data here, passing it through conversion
    template <class other_color_t>
    image(const image<other_color_t> &other,
      converter_t<color_t, other_color_t> *conversion = &default_conversion);

    //directly calls memcpy on the buffer. the second argument does
    //nothing except distinguish this from the other copy constructor.
    image(const image<color_t> &other, bool);

    //use copy constructor and move assignment instead
    image<color_t> &operator =(const image<color_t> &other) = delete;

    ~image();

    void fill(const color_t &color);
    void fill(
      const color_t &color, int start_x, int start_y, int width, int height);

    //does not check bounds
    color_t &at(int x, int y);

    //does not check bounds
    const color_t &at(int x, int y) const;

    image<color_t> stretch(int new_width, int new_height);

    //copies the region here via memcpy. does not check bounds.
    void copy_from(
      const image<color_t> &other, int to_x, int to_y,
      int from_x, int from_y, int width, int height);

    //copies the entire image here via memcpy. does not check bounds.
    void copy_from(const image<color_t> &other, int to_x, int to_y);

    //copies the region here through conversion. does not check bounds.
    template <class other_color_t>
    void convert_from(
      const image<other_color_t> &other, int to_x, int to_y,
      int from_x, int from_y, int width, int height,
      converter_t<color_t, other_color_t> *conversion = &default_conversion);

    //copies the entire image here through conversion. does not check bounds.
    template <class other_color_t>
    void convert_from(
      const image<other_color_t> &other, int to_x, int to_y,
      converter_t<color_t, other_color_t> *conversion = &default_conversion);

    //copies the region here through conversion. does not check bounds.
    template <class other_color_t, class param_t>
    void convert_from(
      const param_t &param, const image<other_color_t> &other, int to_x,
      int to_y, int from_x, int from_y, int width, int height,
      param_converter_t<color_t, other_color_t, param_t> *conversion =
        &default_conversion);

    //copies the entire image here through conversion. does not check bounds.
    template <class other_color_t, class param_t>
    void convert_from(const param_t &param,
      const image<other_color_t> &other, int to_x, int to_y,
      param_converter_t<color_t, other_color_t, param_t> *conversion =
        &default_conversion);

    //does not check bounds or wrap text
    template <class font_color_t, class param_t>
    void render_text(
      const fixed_font<font_color_t> &font,
      const param_t &pararm, int x, int y, const char *text,
      param_converter_t<color_t, font_color_t, param_t> *conversion =
        &default_conversion);

    //does not check bounds or wrap text
    template <class font_color_t>
    void render_text(
      const fixed_font<font_color_t> &font, int x, int y, const char *text,
      converter_t<color_t, font_color_t> *conversion =
        &default_conversion);

  };

  template <class color_t>
  void swap(image<color_t> &a, image<color_t> &b);

}

#include <daguerre/impl/image.hpp>
