#include "GraphicsProxy.h"
#include <stdio.h>

#ifdef WIN32
#include <winsock2.h>
#else
#include <arpa/inet.h>
#endif

GraphicsProxy::GraphicsProxy()
    : stroke_width( 1 )
{
    initSequence();
}

GraphicsProxy::~GraphicsProxy()
{
}

void GraphicsProxy::initSequence()
{
    binaryData.assign( 1, static_cast<char>( OBJ_SEQUENCE_START_CODE ) );
    obj_id = 0;
}

void GraphicsProxy::push8( char x )
{
    binaryData.append( 1, x );
}

void GraphicsProxy::push16( short x )
{
    x = htons( x );
    binaryData.append( reinterpret_cast< char* >( &x ), 2 );
}

void GraphicsProxy::push32( int x )
{
    x = htonl( x );
    binaryData.append( reinterpret_cast< char* >( &x ), 4 );
}

void GraphicsProxy::finalizeSequence()
{
    binaryData.append( 1, static_cast<char>( OBJ_SEQUENCE_END_START_CODE ) );
}

bool GraphicsProxy::drawImage(const Image* img, int x, int y, int width, int height)
{
    // dont expected here
    return false;
}

void GraphicsProxy::drawLine(int x1, int y1, int x2, int y2)
{
    // dont expected here
}

void GraphicsProxy::setColor(Color c)
{
    //fprintf( stderr, "c %d %d %d %d\n", c.r, c.g, c.b, c.a );
    c.swapRB();
    clr = c;
}

void GraphicsProxy::drawRect(int x, int y, int width, int height)
{
    //fprintf( stderr, "bb %d %d %d %d\n", x, y, width, height );
    push8_16( OBJ_START_CODE, obj_id++ );
    push8_8( OBJ_DRAW_TYPE_START_CODE, OBJ_DRAW_TYPE_BOX );
    push8_32( OBJ_COLOR_START_CODE, clr.rgba );
    push8_8( OBJ_LINEWIDTH_START_CODE, (int) ( stroke_width + 0.5 ) );
    push8_16( OBJ_X_COORD_START_CODE, x + width / 2 );
    push8_16( OBJ_Y_COORD_START_CODE, y + height / 2 );
    push8_16( OBJ_WIDTH_START_CODE, width );
    push8_16( OBJ_HEIGHT_START_CODE, height );
}

void GraphicsProxy::fillRect(int x, int y, int width, int height)
{
    // not used??
}

void GraphicsProxy::drawEllipse(int x, int y, int width, int height)
{
    //fprintf( stderr, "el %d %d %d %d\n", x, y, width, height );
    push8_16( OBJ_START_CODE, obj_id++ );
    push8_8( OBJ_DRAW_TYPE_START_CODE, OBJ_DRAW_TYPE_ELLIPSE );
    push8_32( OBJ_COLOR_START_CODE, clr.rgba );
    push8_8( OBJ_LINEWIDTH_START_CODE, (int) ( stroke_width + 0.5 ) );
    push8_16( OBJ_X_COORD_START_CODE, x + width / 2 );
    push8_16( OBJ_Y_COORD_START_CODE, y + height / 2 );
    push8_16( OBJ_WIDTH_START_CODE, width );
    push8_16( OBJ_HEIGHT_START_CODE, height );
}

void GraphicsProxy::fillEllipse(int x, int y, int width, int height)
{
    // not used??
}

void GraphicsProxy::drawPolyline( const std::vector<int>& xCoords, const std::vector<int>& yCoords, int count )
{
    //fprintf( stderr, "poly %d\n", count );
    push8_16( OBJ_START_CODE, obj_id++ );
    push8_8( OBJ_DRAW_TYPE_START_CODE, OBJ_DRAW_TYPE_MLINE );
    push8_32( OBJ_COLOR_START_CODE, clr.rgba );
    push8_8( OBJ_LINEWIDTH_START_CODE, (int) ( stroke_width + 0.5 ) );
    push8_8( OBJ_POLYGON_START_CODE, count );
    for( int i = 0; i < count; i++ ) {
        push16( xCoords[ i ] );
        push16( yCoords[ i ] );
    }
}

void GraphicsProxy::drawPolyline( const std::vector<Point2>& points )
{
    push8_16( OBJ_START_CODE, obj_id++ );
    push8_8( OBJ_DRAW_TYPE_START_CODE, OBJ_DRAW_TYPE_MLINE );
    push8_32( OBJ_COLOR_START_CODE, clr.rgba );
    push8_8( OBJ_LINEWIDTH_START_CODE, (int) ( stroke_width + 0.5 ) );
    push8_8( OBJ_POLYGON_START_CODE, points.size() );
    for( int i = 0, count = points.size(); i < count; i++ ) {
        push16( points[ i ].x );
        push16( points[ i ].y );
    }
}

void GraphicsProxy::fillPolygon( const std::vector<int>& xCoords, const std::vector<int>& yCoords, int count )
{
    push8_16( OBJ_START_CODE, obj_id++ );
    push8_8( OBJ_DRAW_TYPE_START_CODE, OBJ_DRAW_TYPE_POLYGON );
    push8_32( OBJ_COLOR_START_CODE, clr.rgba );
    push8_8( OBJ_LINEWIDTH_START_CODE, (int) ( stroke_width + 0.5 ) );
    push8_8( OBJ_POLYGON_START_CODE, count );
    for( int i = 0; i < count; i++ ) {
        push16( xCoords[ i ] );
        push16( yCoords[ i ] );
    }
}

void GraphicsProxy::fillPolygon( const std::vector<Point2>& points )
{
    push8_16( OBJ_START_CODE, obj_id++ );
    push8_8( OBJ_DRAW_TYPE_START_CODE, OBJ_DRAW_TYPE_POLYGON );
    push8_32( OBJ_COLOR_START_CODE, clr.rgba );
    push8_8( OBJ_LINEWIDTH_START_CODE, (int) ( stroke_width + 0.5 ) );
    push8_8( OBJ_POLYGON_START_CODE, points.size() );
    for( int i = 0, count = points.size(); i < count; i++ ) {
        push16( points[ i ].x );
        push16( points[ i ].y );
    }
}

float GraphicsProxy::getStrokeWidth() const 
{
    return stroke_width;
}

void GraphicsProxy::setStrokeWidth( float strokeWidth )
{
    //fprintf( stderr, "lw %d\n", (int) ( strokeWidth + 0.5 ) );
    stroke_width = strokeWidth;
}


void GraphicsProxy::setFont( const char* fontName, float fontSize, FONT_STYLE fontStyle )
{
    //fprintf( stderr, "sf %g\n", fontSize );
    font_size = fontSize;
}

float GraphicsProxy::fontAscent() const 
{
    return 0; // corrections will be applied in java
}

float GraphicsProxy::fontDescent() const 
{
    return 0; // corrections will be applied in java
}

Point2 GraphicsProxy::measureText( const std::string& text )
{
    return Point2( 0, 0 );
}

Rectangle2 GraphicsProxy::drawString( const std::string& text, float x, float y, HORZ_ALIGN horzAlign, VERT_ALIGN vertAlign )
{
    //fprintf( stderr, "t %g %g `%s'\n", x, y, text.c_str() );
    push8_16( OBJ_START_CODE, obj_id++ );
    push8_8( OBJ_DRAW_TYPE_START_CODE, OBJ_DRAW_TYPE_TEXT );
    push8_32( OBJ_COLOR_START_CODE, clr.rgba );
    push8_16( OBJ_X_COORD_START_CODE, (short) x );
    push8_16( OBJ_Y_COORD_START_CODE, (short) y );
    push8_16( OBJ_HEIGHT_START_CODE, font_size );
    push8_8( OBJ_TEXT_START_CODE, text.size() );
    binaryData.append( text );

    // HACK!
    return Rectangle2( x, y, text.size(), font_size);
}

void GraphicsProxy::pushState()
{
}

void GraphicsProxy::popState()
{
}

void GraphicsProxy::setTransform2Identity()
{
}

void GraphicsProxy::setTransform2( Graphics::Transform2Matrix matrix )
{
}

Graphics::Transform2Matrix GraphicsProxy::getTransform2()
{
    return Graphics::Transform2Matrix( 0, 0, 0, 0, 0, 0 );
}

void GraphicsProxy::multiplyTransform2( Graphics::Transform2Matrix matrix )
{
}

void GraphicsProxy::scaleTransform2( float sx, float sy )
{
}

void GraphicsProxy::rotateTransform2( float angle )
{
}

void GraphicsProxy::translateTransform2( float dx, float dy )
{
}

