#include "node.h"
#include "exports.spm.h"

/*
    static Uint32 ColorRGB(Uint8 R, Uint8 G, Uint8 B);
    static Uint32 GetPixel(SDL_Surface *surface, int x, int y);
    static void FillSquare(SDL_Surface *surface, int point_x, int point_y, int l, Uint32 color);
    static void FillArea(SDL_Surface *surface, int point1_x, int point1_y, int point2_x, int point2_y, Uint32 color);
*/

void SPMPixelCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
    v8::Isolate* isolate = args.GetIsolate();
    if(!args[0]->IsObject()) {
        OverhypeCore::Err(isolate, "Invalid arguments.\n\tRight args: ( surface obligatory, num, num, uint )");
        return;
    }
    int x = 0;
    if(args[1]->IsNumber()) {
        x = args[1].As<v8::Integer>()->Value();
    }
    int y = 0;
    if(args[2]->IsNumber()) {
        y = args[2].As<v8::Integer>()->Value();
    }
    Uint32 color = OverhypeCore::MAIN_COLOR;
    if(args[3]->IsUint32()) {
        color = args[3].As<v8::Uint32>()->Value();
    }
    
    SPM::FillPixel(OverhypeCore::GetSurface(args[0]), x, y, color);
}

void SPMLineCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
    v8::Isolate* isolate = args.GetIsolate();
    if(!args[0]->IsObject()) {
        OverhypeCore::Err(isolate, "Invalid arguments.\n\tRight args: ( surface obligatory, num, num, num, num, uint )");
        return;
    }
    int x1 = 0;
    if(args[1]->IsNumber()) {
        x1 = args[1].As<v8::Integer>()->Value();
    }
    int y1 = 0;
    if(args[2]->IsNumber()) {
        y1 = args[2].As<v8::Integer>()->Value();
    }
    int x2 = 0;
    if(args[3]->IsNumber()) {
        x2 = args[3].As<v8::Integer>()->Value();
    }
    int y2 = 0;
    if(args[4]->IsNumber()) {
        y2 = args[4].As<v8::Integer>()->Value();
    }
    Uint32 color = OverhypeCore::MAIN_COLOR;
    if(args[5]->IsUint32()) {
        color = args[5].As<v8::Uint32>()->Value();
    }
    if(x1 == x2 && y1 == y2 && x1 == y1) {
        SPM::FillPixel(OverhypeCore::GetSurface(args[0]), 0, 0, color);
    } else if(x1 == x2) {
        SPM::VerticalLine(OverhypeCore::GetSurface(args[0]), x1, y1, y2 - y1, color);
    } else if(y1 == y2) {
        SPM::HorizontalLine(OverhypeCore::GetSurface(args[0]), x1, y1, x2 - x1, color);
    } else {
        SPM::Line(OverhypeCore::GetSurface(args[0]), x1, y1, x2, y2, color);
    }
}

void SPMRectCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
    v8::Isolate* isolate = args.GetIsolate();
    if(!args[0]->IsObject()) {
        OverhypeCore::Err(isolate, "Invalid arguments.\n\tRight args: ( surface obligatory, num, num, num, num, uint )");
        return;
    }
    int x1 = 0;
    if(args[1]->IsNumber()) {
        x1 = args[1].As<v8::Integer>()->Value();
    }
    int y1 = 0;
    if(args[2]->IsNumber()) {
        y1 = args[2].As<v8::Integer>()->Value();
    }
    int x2 = 0;
    if(args[3]->IsNumber()) {
        x2 = args[3].As<v8::Integer>()->Value();
    }
    int y2 = 0;
    if(args[4]->IsNumber()) {
        y2 = args[4].As<v8::Integer>()->Value();
    }
    Uint32 color = OverhypeCore::MAIN_COLOR;
    if(args[5]->IsUint32()) {
        color = args[5].As<v8::Uint32>()->Value();
    }
    SPM::Rect(OverhypeCore::GetSurface(args[0]), x1, y1, x2, y2, color);
}
    
void SPMSquareCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
    v8::Isolate* isolate = args.GetIsolate();
    if(!args[0]->IsObject()) {
        OverhypeCore::Err(isolate, "Invalid arguments.\n\tRight args: ( surface obligatory, num, num, num, uint )");
        return;
    }
    int x = 0;
    if(args[1]->IsNumber()) {
        x = args[1].As<v8::Integer>()->Value();
    }
    int y = 0;
    if(args[2]->IsNumber()) {
        y = args[2].As<v8::Integer>()->Value();
    }
    int l = 0;
    if(args[3]->IsNumber()) {
        l = args[3].As<v8::Integer>()->Value();
    }
    Uint32 color = OverhypeCore::MAIN_COLOR;
    if(args[5]->IsUint32()) {
        color = args[5].As<v8::Uint32>()->Value();
    }
    SPM::Square(OverhypeCore::GetSurface(args[0]), x, y, l, color);
}


void SPMCircleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
    v8::Isolate* isolate = args.GetIsolate();
    if(!args[0]->IsObject()) {
        OverhypeCore::Err(isolate, "Invalid arguments.\n\tRight args: ( surface obligatory, num, num, num, uint )");
        return;
    }
    int x = 0;
    if(args[1]->IsNumber()) {
        x = args[1].As<v8::Integer>()->Value();
    }
    int y = 0;
    if(args[2]->IsNumber()) {
        y = args[2].As<v8::Integer>()->Value();
    }
    int r = 0;
    if(args[3]->IsNumber()) {
        r = args[3].As<v8::Integer>()->Value();
    }
    Uint32 color = OverhypeCore::MAIN_COLOR;
    if(args[5]->IsUint32()) {
        color = args[5].As<v8::Uint32>()->Value();
    }
    SPM::Circle(OverhypeCore::GetSurface(args[0]), x, y, r, color);
}

void SPMGridCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
    v8::Isolate* isolate = args.GetIsolate();
    if(!args[0]->IsObject()) {
        OverhypeCore::Err(isolate, "Invalid arguments.\n\tRight args: ( surface obligatory, num, num, num, num, num, uint )");
        return;
    }
    int x1 = 0;
    if(args[1]->IsNumber()) {
        x1 = args[1].As<v8::Integer>()->Value();
    }
    int y1 = 0;
    if(args[2]->IsNumber()) {
        y1 = args[2].As<v8::Integer>()->Value();
    }
    int x2 = 0;
    if(args[3]->IsNumber()) {
        x2 = args[3].As<v8::Integer>()->Value();
    }
    int y2 = 0;
    if(args[4]->IsNumber()) {
        y2 = args[4].As<v8::Integer>()->Value();
    }
    int i = 0;
    if(args[5]->IsNumber()) {
        i = args[5].As<v8::Integer>()->Value();
    }
    Uint32 color = OverhypeCore::MAIN_COLOR;
    if(args[6]->IsUint32()) {
        color = args[6].As<v8::Uint32>()->Value();
    }
    SPM::Grid(OverhypeCore::GetSurface(args[0]), x1, y1, x2, y2, i, color);
}

void SPMBlendedTextCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
    v8::Isolate* isolate = args.GetIsolate();
    if(!args[0]->IsObject()) {
        OverhypeCore::Err(isolate, "Invalid arguments.\n\tRight args: ( surface obligatory, str obligatory, num, num, uint )");
        return;
    }
    if(!args[1]->IsString()) {
        OverhypeCore::Err(isolate, "Invalid arguments.\n\tRight args: ( uint obligatory, str obligatory, num, num, uint )");
        return;
    }
    int x = 0;
    if(args[2]->IsNumber()) {
        x = args[2].As<v8::Integer>()->Value();
    }
    int y = 0;
    if(args[3]->IsNumber()) {
        y = args[3].As<v8::Integer>()->Value();
    }
    Uint32 color = OverhypeCore::MAIN_COLOR;
    if(args[4]->IsUint32()) {
        color = args[4].As<v8::Uint32>()->Value();
    }
    v8::String::Utf8Value str(args[1]);
    std::string text(*str);

    SPM::BlendedText(OverhypeCore::GetSurface(args[0]), text, OverhypeCore::GetCurrentFont(), x, y, color);
}
    


void SPMRotatedSurfaceCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {

    v8::Isolate* isolate = args.GetIsolate();
    if(!args[0]->IsObject()) {
        OverhypeCore::Err(isolate, "Invalid arguments.\n\tRight args: ( surface obligatory, surface obligatory, obj, int, num, int )");
        return;
    }

    if(!args[1]->IsObject()) {
        OverhypeCore::Err(isolate, "Invalid arguments.\n\tRight args: ( surface obligatory, surface obligatory, obj, int, num, int )");
        return;
    }
  
    int x = 0, y = 0;
    if(args[2]->IsObject()) {
        v8::Local<v8::Context> context = isolate->GetCurrentContext();
        v8::Local<v8::Object> obj = args[2]->ToObject(context).ToLocalChecked();
        v8::Local<v8::Array> props = obj->GetOwnPropertyNames(context).ToLocalChecked();

        for(Uint32 i = 0, l = props->Length(); i < l; i++) {
            v8::Local<v8::Value> localKey = props->Get(i);
            v8::Local<v8::Value> localVal = obj->Get(context, localKey).ToLocalChecked();
            std::string key = *v8::String::Utf8Value(localKey);
      
            if(key == "x") {
                x = localVal->IntegerValue();
            } else if (key == "y") { //int
                y = localVal->IntegerValue();
            }
        }
    }

    int angle = 0;
    if(args[3]->IsNumber()) {
        angle = args[3].As<v8::Integer>()->Value();
    }

    double zoom = 1;
    if(args[4]->IsNumber()) {
        zoom = args[4].As<v8::Number>()->Value();
    }

    int smooth = 1;
    if(args[5]->IsNumber()) {
        smooth = args[5].As<v8::Integer>()->Value();
    }

    
    SPM::BlitRotatedSurface(
        OverhypeCore::GetSurface(args[0]),
        OverhypeCore::GetSurface(args[1]),
        x, y,
        angle,
        zoom,
        smooth
    );
}
    

void SPMSliceCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
    v8::Isolate* isolate = args.GetIsolate();
    if(!args[0]->IsObject()) {
        OverhypeCore::Err(isolate, "Invalid arguments.\n\tRight args: ( surface obligatory, num, num, num, num )");
        return;
    }
    int x = 0;
    if(args[1]->IsNumber()) {
        x = args[1].As<v8::Integer>()->Value();
    }
    int y = 0;
    if(args[2]->IsNumber()) {
        y = args[2].As<v8::Integer>()->Value();
    }
    int w = 0;
    if(args[3]->IsNumber()) {
        w = args[3].As<v8::Integer>()->Value();
    }
    int h = 0;
    if(args[4]->IsNumber()) {
        h = args[4].As<v8::Integer>()->Value();
    }

    SDL_Surface *surface = SPM::CutOutSurface(OverhypeCore::GetSurface(args[0]), x, y, w, h);
    Uint32 surfaceId = OverhypeCore::RegisterSurface(surface);
    args.GetReturnValue().Set(OverhypeCore::ReturnSurface(surfaceId, surface->w, surface->h));
}

void SPMFlipCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
    v8::Isolate* isolate = args.GetIsolate();
    if(!args[0]->IsObject()) {
        OverhypeCore::Err(isolate, "Invalid arguments.\n\tRight args: ( surface obligatory, bool, bool )");
        return;
    }
    bool x = 1;
    if(args[1]->IsNumber()) {
        x = args[1].As<v8::Integer>()->Value();
    }
    bool y = 1;
    if(args[2]->IsNumber()) {
        y = args[2].As<v8::Integer>()->Value();
    }

    
    SDL_Surface *surface = SPM::Flip(OverhypeCore::GetSurface(args[0]), x, y);
    Uint32 surfaceId = OverhypeCore::RegisterSurface(surface);
    args.GetReturnValue().Set(OverhypeCore::ReturnSurface(surfaceId, surface->w, surface->h));
}



void RegisterSPM(v8::Local<v8::Object> exports) {
    v8::Isolate* isolate = v8::Isolate::GetCurrent();
    v8::Local<v8::Object> spm = v8::Object::New(isolate);
    exports->Set(v8::String::NewFromUtf8(isolate, "spm"), spm);

    NODE_SET_METHOD(spm, "pixel", SPMPixelCallback);
    NODE_SET_METHOD(spm, "line", SPMLineCallback);
    NODE_SET_METHOD(spm, "rect", SPMRectCallback);
    NODE_SET_METHOD(spm, "square", SPMSquareCallback);
    NODE_SET_METHOD(spm, "circle", SPMCircleCallback);
    NODE_SET_METHOD(spm, "grid", SPMGridCallback);
    NODE_SET_METHOD(spm, "blendedText", SPMBlendedTextCallback);
    NODE_SET_METHOD(spm, "rotatedSurface", SPMRotatedSurfaceCallback);
    NODE_SET_METHOD(spm, "slice", SPMSliceCallback);
    NODE_SET_METHOD(spm, "flip", SPMFlipCallback);
}