#pragma once
#include "common.hpp"
#include "colors.hpp"


class Buf {
    private:
        unsigned char* const buf;
        bool proxy;
        const unsigned off_x, off_y;
        const unsigned width, height;

    public:
        Buf(unsigned, unsigned);
        Buf(const Buf&); // deep copy
        Buf(Buf*, unsigned, unsigned, unsigned, unsigned); // proxy (TODO: split into accessor interface and proxy delegator subclass)
        ~Buf();

        unsigned char* ptr(unsigned x, unsigned y) { assert(x<w && y<h); return buf + ((y+off_y)*width*3) + ((x+off_x)*3); }
        const unsigned char* ptr(unsigned x, unsigned y) const { assert(x<w && y<h); return buf + ((y+off_y)*width*3) + ((x+off_x)*3); }

        rgb_t& at(unsigned x, unsigned y) { return (*(rgb_t*)ptr(x, y)); }
        const rgb_t& at(unsigned x, unsigned y) const { return (*(const rgb_t*)ptr(x, y)); }
        unsigned char* at(unsigned y) { return ptr(0, y); }
        const unsigned char* at(unsigned y) const { return ptr(0, y); }

        const unsigned w, h;
};


class Image {
    public:
        Buf buf;

        Image(unsigned w, unsigned h): buf(w, h) {}
        Image(const Image& other): buf(other.buf) {}
        Image(Buf* b, unsigned x, unsigned y, unsigned w, unsigned h): buf(b, x, y, w, h) {}

        void put(unsigned, unsigned, const Image*);
        Image* box(unsigned) const;
        Image* boxed(unsigned x, unsigned y, unsigned w, unsigned h);
        rgb_t avg() const { return avg(0, 0, buf.w, buf.h); }
        rgb_t avg(unsigned x, unsigned y, unsigned w, unsigned h) const;
        rgb_t med() const { return med(0, 0, buf.w, buf.h); }
        rgb_t med(unsigned x, unsigned y, unsigned w, unsigned h) const;
        rgb_t palette_max(unsigned x, unsigned y, unsigned w, unsigned h) const;
        unsigned char dist(const rgb_t&) const;
        unsigned char dist(const Image*) const;
        double fdist(const Image*) const;
        void tint(unsigned x, unsigned y, unsigned w, unsigned h, const rgb_t&, unsigned char alpha);
        void tint(const Image*, unsigned char alpha);
};