#include "GraphicsGDImpl.h"
#include <stdio.h>
#include <stdarg.h>

GraphicsGDImpl::GraphicsGDImpl(gdImagePtr im /*uint8_t* data, unsigned& dataSize*/)
    : Graphics()
    , im_(im)
    , strokeWidth_(3.0f)
    , f_(NULL)
{
    color_ = gdImageColorAllocate(im_, 0, 0, 0);
#ifdef DEBUG_CALL_FUNC
    f_ = fopen("/tmp/gd_debug.log", "w");
#endif
//    if(im_ == NULL) throw std::bad_alloc("corrupted JPEG, skip it")
}

int GraphicsGDImpl::fprintf(FILE* f, const char *fmt, ...)
{
    if (!f)
        return 0;

    va_list ap;
    va_start(ap, fmt);
    int ret = ::fprintf(f, fmt, ap);
    va_end(ap);

    return ret;
}

GraphicsGDImpl::~GraphicsGDImpl()
{
    /*uint8_t* buf = (uint8_t*)gdImageJpegPtr(im_, pDataSize_, 80);
    memcpy(data_, buf, dataSize_);
    gdFree(buf);
    fprintf("im size=%d\n", *pDataSize_);
    gdImageDestroy(im_);*/
    if(f_)
        fclose(f_);
}

void GraphicsGDImpl::drawLine(int x1, int y1, int x2, int y2)
{
    fprintf(f_, "drawLine()\n");
    // Background color (first allocated)
    //int black = gdImageColorAllocate(im_, 0, 0, 0);
    gdImageSetAntiAliased(im_, color_);
    gdImageLine(im_, x1, y1, x2, y2, gdAntiAliased);
}

void GraphicsGDImpl::setColor(Color c)
{
    fprintf(f_, "setColor(r=%d, g=%d, b=%d, a=%d)\n", c.r, c.g, c.b, c.a);
    // Background color (first allocated)
    //int black = gdImageColorAllocate(im_, 0, 0, 0);
    if(c.a == 255)
        color_ = gdImageColorAllocate(im_, c.r, c.g, c.b);
    else {
        color_ = gdTrueColorAlpha(c.r, c.g, c.b, gdAlphaTransparent - c.a/2);
        gdImageAlphaBlending(im_, 1);
    }
}

void GraphicsGDImpl::drawRect(int x, int y, int width, int height)
{
    fprintf(f_, "drawRect()\n");
    gdImageSetAntiAliased(im_, color_);
    gdImageRectangle(im_, x, y, x + width, y + height, color_);
}

void GraphicsGDImpl::fillRect(int x, int y, int width, int height)
{
    fprintf(f_, "fillRect()\n");
    gdImageSetAntiAliased(im_, color_);
    gdImageFilledRectangle(im_, x, y, x + width, y + height, color_);
}

void GraphicsGDImpl::drawEllipse(int x, int y, int width, int height)
{
    fprintf(f_, "drawEllipse()\n");
    gdImageArc(im_, x, y, width, height, 0, 360, color_);
}

void GraphicsGDImpl::fillEllipse(int x, int y, int width, int height)
{
    fprintf(f_, "fillEllipse()\n");
    gdImageFilledEllipse(im_, x, y, width, height, color_);
}

void GraphicsGDImpl::drawPolyline( const std::vector<int>& xCoords, const std::vector<int>& yCoords, int count )
{
    fprintf(f_, "drawPolyline()\n");
    gdPointPtr points = new gdPoint[count];
    for(int i=0; i<count; i++) {
        points[i].x = xCoords[i];
        points[i].y = yCoords[i];
    }
    gdImageSetAntiAliased(im_, color_);
    gdImageOpenPolygon(im_, points, count, color_);
    delete[] points;
}

void GraphicsGDImpl::drawPolyline( const std::vector<Point2>& pts )
{
    fprintf(f_, "drawPolyline()\n");
    gdPointPtr points = new gdPoint[pts.size()];
    for(size_t i=0; i<pts.size(); i++) {
        points[i].x = pts[i].x;
        points[i].y = pts[i].y;
    }
    gdImageSetAntiAliased(im_, color_);
    gdImageOpenPolygon(im_, points, pts.size(), color_);
    delete[] points;
}

void GraphicsGDImpl::fillPolygon( const std::vector<int>& xCoords, const std::vector<int>& yCoords, int count )
{
    fprintf(f_, "fillPolygon()\n");
    gdPointPtr points = new gdPoint[count];
    for(int i=0; i<count; i++) {
        points[i].x = xCoords[i];
        points[i].y = yCoords[i];
    }
    gdImageSetAntiAliased(im_, color_);
    gdImageFilledPolygon(im_, points, count, color_);
    delete[] points;
}

void GraphicsGDImpl::fillPolygon( const std::vector<Point2>& pts )
{
    fprintf(f_, "fillPolygon()\n");
    gdPointPtr points = new gdPoint[pts.size()];
    for(size_t i=0; i<pts.size(); i++) {
        points[i].x = pts[i].x;
        points[i].y = pts[i].y;
    }
    gdImageSetAntiAliased(im_, color_);
    gdImageFilledPolygon(im_, points, pts.size(), color_);
    delete[] points;
}

float GraphicsGDImpl::getStrokeWidth() const
{
    fprintf(f_, "getStrokeWidth()\n");
    return strokeWidth_;
}

void GraphicsGDImpl::setStrokeWidth( float strokeWidth )
{
    fprintf(f_, "setStrokeWidth()\n");
    gdImageSetThickness(im_, (int)strokeWidth);
}

void GraphicsGDImpl::setFont( const char* fontName, float fontSize, FONT_STYLE fontStyle )
{
    fprintf(f_, "setFont(): fontName=%s, fontSize=%.1f, fontStyle=%d\n",
            fontName, fontSize, fontStyle);
}

float GraphicsGDImpl::fontAscent() const
{
    fprintf(f_, "fontAscent()\n");
    return 0.0f;
}

float GraphicsGDImpl::fontDescent() const
{
    fprintf(f_, "fontDescent()\n");
    return 0.0f;
}

Point2 GraphicsGDImpl::measureText( const std::string& text )
{
    fprintf(f_, "measureText(%s)\n", text.c_str());
    return Point2(0, 0);
//    QRect rect = (fontMetrics_) ? fontMetrics_->boundingRect(text.c_str()) : QRect();
//    return Point2(rect.width(), rect.height() + fontAscent() + fontDescent());
}

Rectangle2 GraphicsGDImpl::drawString( const std::string& text, float x, float y, HORZ_ALIGN horzAlign, VERT_ALIGN vertAlign )
{
    fprintf(f_, "drawString(%s)\n", text.c_str());
    return Rectangle2(0, 0, x, y);

    /*Point2 pt = measureText(text);
    float asc = fontAscent();
    float desc = fontDescent();
    if(horzAlign == Center)
        x -= pt.x/2.f;
    else if(horzAlign == Right)
        x -= pt.x;
    if(x<0) x=0;

    if(vertAlign == Middle)
        y += asc/2.f;
    else if(vertAlign == Top)
        y += asc;
    else if(vertAlign == Bottom)
        y -= desc;
    if(y<0) y=0;

    painter_.drawText((int)x, (int)y, text.c_str());
    return Rectangle2(x, y - asc, pt.x, pt.y);*/
}
