// addon.cc
#include <node.h>
#include "nan.h"
#include <Windows.h>
#include <fstream>
#include <sstream>
#include <string>
#include <iostream>

namespace demo {

using v8::Exception;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::Isolate;
using v8::Local;
using v8::Object;
using v8::String;
using v8::Value;


int abc = 1234;

const HDC dc = GetDC(NULL);

/*
DOCUMENTATION:

make a function that returns a value:

	void MyFunction(const FunctionCallbackInfo<Value>& args) {
      Isolate* isolate = args.GetIsolate(VALUE); or args.GetIsolate(String::NewFromUtf8("TEXT"));
      args.GetReturnValue().Set(abc);
    }
	
	
Add it to init:

	NODE_SET_METHOD(exports, "NAME", FUNCTION_NAME);

*/

void MyFunction(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();
  args.GetReturnValue().Set(abc);
}


void ChangeBrush(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();
  
  if (args.Length() < 3) {
    // Throw an Error that is passed back to JavaScript
    isolate->ThrowException(Exception::TypeError(
        String::NewFromUtf8(isolate, "Wrong number of arguments")));
    return;
  }
  
   if (!args[0]->IsNumber() || !args[1]->IsNumber() || !args[2]->IsNumber()) {
    isolate->ThrowException(Exception::TypeError(
        String::NewFromUtf8(isolate, "Wrong arguments")));
    return;
  }
  
  SelectObject(dc, GetStockObject(DC_PEN));
  SelectObject(dc, GetStockObject(DC_BRUSH));

  SetDCBrushColor(dc, RGB(args[0]->Uint32Value(), args[1]->Uint32Value(), args[2]->Uint32Value()));
  SetDCPenColor(dc, RGB(args[0]->Uint32Value(), args[1]->Uint32Value(), args[2]->Uint32Value()));
  
  args.GetReturnValue().Set(String::NewFromUtf8(isolate, "success"));
}


void MoveTo(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();
  
  if (args.Length() < 2) {
    // Throw an Error that is passed back to JavaScript
    isolate->ThrowException(Exception::TypeError(
        String::NewFromUtf8(isolate, "Wrong number of arguments")));
    return;
  }
  
   if (!args[0]->IsNumber() || !args[1]->IsNumber()) {
    isolate->ThrowException(Exception::TypeError(
        String::NewFromUtf8(isolate, "Wrong arguments")));
    return;
  }
  
  MoveToEx(dc, args[0]->Uint32Value(), args[1]->Uint32Value(), NULL);
  args.GetReturnValue().Set(1);
}


void LineTo1(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();
  
  if (args.Length() < 2) {
    // Throw an Error that is passed back to JavaScript
    isolate->ThrowException(Exception::TypeError(
        String::NewFromUtf8(isolate, "Wrong number of arguments")));
    return;
  }
  
   if (!args[0]->IsNumber() || !args[1]->IsNumber()) {
    isolate->ThrowException(Exception::TypeError(
        String::NewFromUtf8(isolate, "Wrong arguments")));
    return;
  }
  
  
  LineTo(dc, args[0]->Uint32Value(), args[1]->Uint32Value());
  args.GetReturnValue().Set(1);
}


void Rectangle(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();
  
  if (args.Length() < 4) {
    // Throw an Error that is passed back to JavaScript
    isolate->ThrowException(Exception::TypeError(
        String::NewFromUtf8(isolate, "Wrong number of arguments")));
    return;
  }
  
   if (!args[0]->IsNumber() || !args[1]->IsNumber() || !args[2]->IsNumber() || !args[3]->IsNumber()) {
    isolate->ThrowException(Exception::TypeError(
        String::NewFromUtf8(isolate, "Wrong arguments")));
    return;
  }
  
  SelectObject(dc, GetStockObject(NULL_BRUSH));
  Rectangle(dc, args[0]->Uint32Value(), args[1]->Uint32Value(), args[0]->Uint32Value()+ args[2]->Uint32Value(), args[1]->Uint32Value() + args[3]->Uint32Value());
  args.GetReturnValue().Set(1);
}


/*     COLORS     */

//R
void pxR(const FunctionCallbackInfo<Value>& args) { //Get r
  Isolate* isolate = args.GetIsolate();
  
  if (args.Length() < 2) {
    // Throw an Error that is passed back to JavaScript
    isolate->ThrowException(Exception::TypeError(
        String::NewFromUtf8(isolate, "Wrong number of arguments")));
    return;
  }
  
   if (!args[0]->IsNumber() || !args[1]->IsNumber()) {
    isolate->ThrowException(Exception::TypeError(
        String::NewFromUtf8(isolate, "Wrong arguments")));
    return;
  }
  
    COLORREF color = GetPixel(dc, args[0]->Uint32Value(), args[1]->Uint32Value());
    
	auto r = GetRValue(color);

    args.GetReturnValue().Set(r);
}

//G
void pxG(const FunctionCallbackInfo<Value>& args) { //Get g
  Isolate* isolate = args.GetIsolate();
  
  if (args.Length() < 2) {
    // Throw an Error that is passed back to JavaScript
    isolate->ThrowException(Exception::TypeError(
        String::NewFromUtf8(isolate, "Wrong number of arguments")));
    return;
  }
  
   if (!args[0]->IsNumber() || !args[1]->IsNumber()) {
    isolate->ThrowException(Exception::TypeError(
        String::NewFromUtf8(isolate, "Wrong arguments")));
    return;
  }
  
    COLORREF color = GetPixel(dc, args[0]->Uint32Value(), args[1]->Uint32Value());
    
	auto g = GetGValue(color);

    args.GetReturnValue().Set(g);
}

//B
void pxB(const FunctionCallbackInfo<Value>& args) { //Get b
  Isolate* isolate = args.GetIsolate();
  
  if (args.Length() < 2) {
    // Throw an Error that is passed back to JavaScript
    isolate->ThrowException(Exception::TypeError(
        String::NewFromUtf8(isolate, "Wrong number of arguments")));
    return;
  }
  
   if (!args[0]->IsNumber() || !args[1]->IsNumber()) {
    isolate->ThrowException(Exception::TypeError(
        String::NewFromUtf8(isolate, "Wrong arguments")));
    return;
  }
  
    COLORREF color = GetPixel(dc, args[0]->Uint32Value(), args[1]->Uint32Value());
    
	auto b = GetBValue(color);

    args.GetReturnValue().Set(b);
}


/*   MOUSE MOVEMENT   */
void moveMouse(const FunctionCallbackInfo<Value>& args) { //for games
  Isolate* isolate = args.GetIsolate();
  
  if (args.Length() < 2) {
    // Throw an Error that is passed back to JavaScript
    isolate->ThrowException(Exception::TypeError(
        String::NewFromUtf8(isolate, "Wrong number of arguments")));
    return;
  }
  
   if (!args[0]->IsNumber() || !args[1]->IsNumber()) {
    isolate->ThrowException(Exception::TypeError(
        String::NewFromUtf8(isolate, "Wrong arguments")));
    return;
  }
  
    INPUT mouseInput;
	mouseInput.type = INPUT_MOUSE;
	mouseInput.mi.dx = args[0]->Uint32Value();
	mouseInput.mi.dy = args[1]->Uint32Value();
	mouseInput.mi.dwFlags = MOUSEEVENTF_MOVE;
	mouseInput.mi.time = 0; //System will provide the timestamp
	mouseInput.mi.dwExtraInfo = 0;
	mouseInput.mi.mouseData = 0;
	SendInput(1, &mouseInput, sizeof(mouseInput));


    args.GetReturnValue().Set(1);
}


void init(Local<Object> exports) {
  NODE_SET_METHOD(exports, "changeColor", ChangeBrush);
  NODE_SET_METHOD(exports, "moveTo", MoveTo);
  NODE_SET_METHOD(exports, "lineTo", LineTo1);
  NODE_SET_METHOD(exports, "rect", Rectangle);
  NODE_SET_METHOD(exports, "getR", pxR);
  NODE_SET_METHOD(exports, "getG", pxG);
  NODE_SET_METHOD(exports, "getB", pxB);
  NODE_SET_METHOD(exports, "target", moveMouse);
  NODE_SET_METHOD(exports, "test", MyFunction);
};

NODE_MODULE(NODE_GYP_MODULE_NAME, init)

}  // namespace demo