// This is a generated file, modify: generate/templates/struct_content.cc.
#include <nan.h>
#include <string.h>
#include <chrono>
#include <thread>

extern "C" {
  #include <git2.h>
 }

#include <iostream>
#include "../include/functions/copy.h"
#include "../include/diff_options.h"

  #include "../include/strarray.h"
  #include "../include/diff.h"
  #include "../include/diff_delta.h"
 
using namespace v8;
using namespace node;
using namespace std;


// generated from struct_content.cc
GitDiffOptions::GitDiffOptions() {
  git_diff_options wrappedValue = GIT_DIFF_OPTIONS_INIT;
  this->raw = (git_diff_options*) malloc(sizeof(git_diff_options));
  memcpy(this->raw, &wrappedValue, sizeof(git_diff_options));

  this->ConstructFields();
  this->selfFreeing = true;
}

GitDiffOptions::GitDiffOptions(git_diff_options* raw, bool selfFreeing) {
  this->raw = raw;
  this->ConstructFields();
  this->selfFreeing = selfFreeing;
}

GitDiffOptions::~GitDiffOptions() {
  // This is going to cause memory leaks. We'll have to solve that later
  // TODO: Clean up memory better
  if (this->selfFreeing) {
    free(this->raw);
  }
}

void GitDiffOptions::ConstructFields() {
                  Local<Object> pathspecTemp = GitStrarray::New(
            &this->raw->pathspec,
            false
          )->ToObject();
          NanAssignPersistent(this->pathspec, pathspecTemp);

   
          // Set the static method call and set the payload for this function to be
          // the current instance
          this->raw->notify_cb = (git_diff_notify_cb)notify_cb_cppCallback;
          this->raw->notify_payload = (void *)this;
          this->notify_cb = new NanCallback();
   
          Local<Value> notify_payload = NanUndefined();
          NanAssignPersistent(this->notify_payload, notify_payload);
                     }

void GitDiffOptions::InitializeComponent(Handle<v8::Object> target) {
  NanScope();

  Local<FunctionTemplate> tpl = NanNew<FunctionTemplate>(JSNewFunction);

  tpl->InstanceTemplate()->SetInternalFieldCount(1);
  tpl->SetClassName(NanNew<String>("DiffOptions"));

      tpl->InstanceTemplate()->SetAccessor(NanNew<String>("version"), GetVersion, SetVersion);
       tpl->InstanceTemplate()->SetAccessor(NanNew<String>("flags"), GetFlags, SetFlags);
       tpl->InstanceTemplate()->SetAccessor(NanNew<String>("ignoreSubmodules"), GetIgnoreSubmodules, SetIgnoreSubmodules);
       tpl->InstanceTemplate()->SetAccessor(NanNew<String>("pathspec"), GetPathspec, SetPathspec);
       tpl->InstanceTemplate()->SetAccessor(NanNew<String>("notifyCb"), GetNotifyCb, SetNotifyCb);
       tpl->InstanceTemplate()->SetAccessor(NanNew<String>("notifyPayload"), GetNotifyPayload, SetNotifyPayload);
       tpl->InstanceTemplate()->SetAccessor(NanNew<String>("contextLines"), GetContextLines, SetContextLines);
       tpl->InstanceTemplate()->SetAccessor(NanNew<String>("interhunkLines"), GetInterhunkLines, SetInterhunkLines);
       tpl->InstanceTemplate()->SetAccessor(NanNew<String>("idAbbrev"), GetIdAbbrev, SetIdAbbrev);
       tpl->InstanceTemplate()->SetAccessor(NanNew<String>("maxSize"), GetMaxSize, SetMaxSize);
       tpl->InstanceTemplate()->SetAccessor(NanNew<String>("oldPrefix"), GetOldPrefix, SetOldPrefix);
       tpl->InstanceTemplate()->SetAccessor(NanNew<String>("newPrefix"), GetNewPrefix, SetNewPrefix);
  
  Local<Function> _constructor_template = tpl->GetFunction();
  NanAssignPersistent(constructor_template, _constructor_template);
  target->Set(NanNew<String>("DiffOptions"), _constructor_template);
}

NAN_METHOD(GitDiffOptions::JSNewFunction) {
  NanScope();
  GitDiffOptions* instance;

  if (args.Length() == 0 || !args[0]->IsExternal()) {
    instance = new GitDiffOptions();
  }
  else {
    instance = new GitDiffOptions(static_cast<git_diff_options*>(Handle<External>::Cast(args[0])->Value()), args[1]->BooleanValue());
  }

  instance->Wrap(args.This());

  NanReturnValue(args.This());
}

Handle<Value> GitDiffOptions::New(void* raw, bool selfFreeing) {
  NanEscapableScope();

  Handle<Value> argv[2] = { NanNew<External>((void *)raw), NanNew<Boolean>(selfFreeing) };
  return NanEscapeScope(NanNew<Function>(GitDiffOptions::constructor_template)->NewInstance(2, argv));
}

git_diff_options *GitDiffOptions::GetValue() {
  return this->raw;
}

git_diff_options **GitDiffOptions::GetRefValue() {
  return &this->raw;
}

    NAN_GETTER(GitDiffOptions::GetVersion) {
      NanScope();

      GitDiffOptions *wrapper = ObjectWrap::Unwrap<GitDiffOptions>(args.This());

        NanReturnValue(NanNew<Number>(wrapper->GetValue()->version));
     }

    NAN_SETTER(GitDiffOptions::SetVersion) {
      NanScope();

      GitDiffOptions *wrapper = ObjectWrap::Unwrap<GitDiffOptions>(args.This());

         if (value->IsNumber()) {
          wrapper->GetValue()->version = (unsigned int) value->Int32Value();
        }
     }

      NAN_GETTER(GitDiffOptions::GetFlags) {
      NanScope();

      GitDiffOptions *wrapper = ObjectWrap::Unwrap<GitDiffOptions>(args.This());

        NanReturnValue(NanNew<Number>(wrapper->GetValue()->flags));
     }

    NAN_SETTER(GitDiffOptions::SetFlags) {
      NanScope();

      GitDiffOptions *wrapper = ObjectWrap::Unwrap<GitDiffOptions>(args.This());

         if (value->IsNumber()) {
          wrapper->GetValue()->flags = (uint32_t) value->Int32Value();
        }
     }

      NAN_GETTER(GitDiffOptions::GetIgnoreSubmodules) {
      NanScope();

      GitDiffOptions *wrapper = ObjectWrap::Unwrap<GitDiffOptions>(args.This());

        NanReturnValue(NanNew((int)wrapper->GetValue()->ignore_submodules));

     }

    NAN_SETTER(GitDiffOptions::SetIgnoreSubmodules) {
      NanScope();

      GitDiffOptions *wrapper = ObjectWrap::Unwrap<GitDiffOptions>(args.This());

        if (value->IsNumber()) {
          wrapper->GetValue()->ignore_submodules = (git_submodule_ignore_t) value->Int32Value();
        }

     }

      NAN_GETTER(GitDiffOptions::GetPathspec) {
      NanScope();

      GitDiffOptions *wrapper = ObjectWrap::Unwrap<GitDiffOptions>(args.This());

        NanReturnValue(wrapper->pathspec);

     }

    NAN_SETTER(GitDiffOptions::SetPathspec) {
      NanScope();

      GitDiffOptions *wrapper = ObjectWrap::Unwrap<GitDiffOptions>(args.This());

        NanDisposePersistent(wrapper->pathspec);
        wrapper->raw->pathspec = * ObjectWrap::Unwrap<GitStrarray>(value->ToObject())->GetValue();

     }

      NAN_GETTER(GitDiffOptions::GetNotifyCb) {
      NanScope();

      GitDiffOptions *wrapper = ObjectWrap::Unwrap<GitDiffOptions>(args.This());

        NanReturnValue(wrapper->notify_cb->GetFunction());

     }

    NAN_SETTER(GitDiffOptions::SetNotifyCb) {
      NanScope();

      GitDiffOptions *wrapper = ObjectWrap::Unwrap<GitDiffOptions>(args.This());

        if (value->IsFunction()) {
          wrapper->notify_cb = new NanCallback(value.As<Function>());
        }

     }

      int GitDiffOptions::notify_cb_cppCallback (
          const git_diff * diff_so_far,           git_diff_delta * delta_to_add,           const char * matched_pathspec,           void * payload        ) {
        NotifyCbBaton* baton = new NotifyCbBaton();

          baton->diff_so_far = diff_so_far;
          baton->delta_to_add = delta_to_add;
          baton->matched_pathspec = matched_pathspec;
          baton->payload = payload;
 
        baton->req.data = baton;
        baton->done = false;

        uv_queue_work(uv_default_loop(), &baton->req, notify_cb_asyncWork, notify_cb_asyncAfter);

        while(!baton->done) {
          this_thread::sleep_for(chrono::milliseconds(1));
        }

 
        return baton->result;
      }

      void GitDiffOptions::notify_cb_asyncWork(uv_work_t* req) {
        // We aren't doing any work on a seperate thread, just need to
        // access the main node thread in the async after method.
        // However, this worker method is still needed
      }

      void GitDiffOptions::notify_cb_asyncAfter(uv_work_t* req, int status) {
        NanScope();

        NotifyCbBaton* baton = static_cast<NotifyCbBaton*>(req->data);
        GitDiffOptions* instance = static_cast<GitDiffOptions*>(baton->payload);

        if (instance->notify_cb->IsEmpty()) {
            baton->result = 1; // no results acquired
 
          baton->done = true;
          return;
        }

        Local<Value> argv[4] = {
                NanNew(GitDiff::New(&baton->diff_so_far, false)),
                  NanNew(GitDiffDelta::New(&baton->delta_to_add, false)),
                   NanNew(baton->matched_pathspec),
                NanNew(instance->notify_payload)
          };

        TryCatch tryCatch;
        Handle<Value> result = instance->notify_cb->Call(4, argv);

        if (result->IsObject() && result->ToObject()->Has(NanNew("then"))) {
          Handle<Value> thenProp = result->ToObject()->Get(NanNew("then"));

          if (thenProp->IsFunction()) {
            // we can be reasonbly certain that the result is a promise
            Local<Object> promise = result->ToObject();

            NanAssignPersistent(baton->promise, promise);

            uv_queue_work(uv_default_loop(), &baton->req, notify_cb_asyncWork, notify_cb_asyncPromisePolling);
            return;
          }
        }

        int resultStatus;

         baton->done = true;
      }

      void GitDiffOptions::notify_cb_asyncPromisePolling(uv_work_t* req, int status) {
        NanScope();

        NotifyCbBaton* baton = static_cast<NotifyCbBaton*>(req->data);
        Local<Object> promise = NanNew<Object>(baton->promise);
        NanCallback* isPendingFn = new NanCallback(promise->Get(NanNew("isPending")).As<Function>());
        Local<Value> argv[1]; // MSBUILD won't assign an array of length 0
        Local<Boolean> isPending = isPendingFn->Call(0, argv)->ToBoolean();

        if (isPending->Value()) {
          uv_queue_work(uv_default_loop(), &baton->req, notify_cb_asyncWork, notify_cb_asyncPromisePolling);
          return;
        }

        NanCallback* isFulfilledFn = new NanCallback(promise->Get(NanNew("isFulfilled")).As<Function>());
        Local<Boolean> isFulfilled = isFulfilledFn->Call(0, argv)->ToBoolean();

        if (isFulfilled->Value()) {
          NanCallback* resultFn = new NanCallback(promise->Get(NanNew("value")).As<Function>());
          Handle<Value> result = resultFn->Call(0, argv);
          int resultStatus;

           baton->done = true;
        }
        else {
          // promise was rejected
          baton->result = -1;
          baton->done = false;
        }
      }
      NAN_GETTER(GitDiffOptions::GetNotifyPayload) {
      NanScope();

      GitDiffOptions *wrapper = ObjectWrap::Unwrap<GitDiffOptions>(args.This());

        NanReturnValue(wrapper->notify_payload);

     }

    NAN_SETTER(GitDiffOptions::SetNotifyPayload) {
      NanScope();

      GitDiffOptions *wrapper = ObjectWrap::Unwrap<GitDiffOptions>(args.This());

        NanAssignPersistent(wrapper->notify_payload, value);

     }

      NAN_GETTER(GitDiffOptions::GetContextLines) {
      NanScope();

      GitDiffOptions *wrapper = ObjectWrap::Unwrap<GitDiffOptions>(args.This());

        NanReturnValue(NanNew<Number>(wrapper->GetValue()->context_lines));
     }

    NAN_SETTER(GitDiffOptions::SetContextLines) {
      NanScope();

      GitDiffOptions *wrapper = ObjectWrap::Unwrap<GitDiffOptions>(args.This());

         if (value->IsNumber()) {
          wrapper->GetValue()->context_lines = (uint16_t) value->Int32Value();
        }
     }

      NAN_GETTER(GitDiffOptions::GetInterhunkLines) {
      NanScope();

      GitDiffOptions *wrapper = ObjectWrap::Unwrap<GitDiffOptions>(args.This());

        NanReturnValue(NanNew<Number>(wrapper->GetValue()->interhunk_lines));
     }

    NAN_SETTER(GitDiffOptions::SetInterhunkLines) {
      NanScope();

      GitDiffOptions *wrapper = ObjectWrap::Unwrap<GitDiffOptions>(args.This());

         if (value->IsNumber()) {
          wrapper->GetValue()->interhunk_lines = (uint16_t) value->Int32Value();
        }
     }

      NAN_GETTER(GitDiffOptions::GetIdAbbrev) {
      NanScope();

      GitDiffOptions *wrapper = ObjectWrap::Unwrap<GitDiffOptions>(args.This());

        NanReturnValue(NanNew<Number>(wrapper->GetValue()->id_abbrev));
     }

    NAN_SETTER(GitDiffOptions::SetIdAbbrev) {
      NanScope();

      GitDiffOptions *wrapper = ObjectWrap::Unwrap<GitDiffOptions>(args.This());

         if (value->IsNumber()) {
          wrapper->GetValue()->id_abbrev = (uint16_t) value->Int32Value();
        }
     }

      NAN_GETTER(GitDiffOptions::GetMaxSize) {
      NanScope();

      GitDiffOptions *wrapper = ObjectWrap::Unwrap<GitDiffOptions>(args.This());

        NanReturnValue(NanNew((int)wrapper->GetValue()->max_size));

     }

    NAN_SETTER(GitDiffOptions::SetMaxSize) {
      NanScope();

      GitDiffOptions *wrapper = ObjectWrap::Unwrap<GitDiffOptions>(args.This());

        if (value->IsNumber()) {
          wrapper->GetValue()->max_size = (git_off_t) value->Int32Value();
        }

     }

      NAN_GETTER(GitDiffOptions::GetOldPrefix) {
      NanScope();

      GitDiffOptions *wrapper = ObjectWrap::Unwrap<GitDiffOptions>(args.This());

        if (wrapper->GetValue()->old_prefix) {
          NanReturnValue(NanNew<String>(wrapper->GetValue()->old_prefix));
        }
        else {
          NanReturnUndefined();
        }

     }

    NAN_SETTER(GitDiffOptions::SetOldPrefix) {
      NanScope();

      GitDiffOptions *wrapper = ObjectWrap::Unwrap<GitDiffOptions>(args.This());

        if (wrapper->GetValue()->old_prefix) {
        }

        String::Utf8Value str(value);
        wrapper->GetValue()->old_prefix = strdup(*str);

     }

      NAN_GETTER(GitDiffOptions::GetNewPrefix) {
      NanScope();

      GitDiffOptions *wrapper = ObjectWrap::Unwrap<GitDiffOptions>(args.This());

        if (wrapper->GetValue()->new_prefix) {
          NanReturnValue(NanNew<String>(wrapper->GetValue()->new_prefix));
        }
        else {
          NanReturnUndefined();
        }

     }

    NAN_SETTER(GitDiffOptions::SetNewPrefix) {
      NanScope();

      GitDiffOptions *wrapper = ObjectWrap::Unwrap<GitDiffOptions>(args.This());

        if (wrapper->GetValue()->new_prefix) {
        }

        String::Utf8Value str(value);
        wrapper->GetValue()->new_prefix = strdup(*str);

     }

   
Persistent<Function> GitDiffOptions::constructor_template;
