// This is a generated file, modify: generate/templates/templates/class_content.cc

#include <nan.h>
#include <string.h>

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

#include "../include/nodegit.h"
#include "../include/lock_master.h"
#include "../include/functions/copy.h"
#include "../include/email.h"
#include "nodegit_wrapper.cc"

  #include "../include/buf.h"
  #include "../include/commit.h"
  #include "../include/email_create_options.h"
  #include "../include/diff.h"
  #include "../include/oid.h"
  #include "../include/signature.h"
 
#include <iostream>

using namespace std;
using namespace v8;
using namespace node;

 
  void GitEmail::InitializeComponent(v8::Local<v8::Object> target, nodegit::Context *nodegitContext) {
    Nan::HandleScope scope;
    Local<External> nodegitExternal = Nan::New<External>(nodegitContext);

       v8::Local<Object> object = Nan::New<Object>();
         Nan::SetMethod(object, "createFromCommit", CreateFromCommit, nodegitExternal);
         Nan::SetMethod(object, "createFromDiff", CreateFromDiff, nodegitExternal);
  
    Nan::Set(
      target,
      Nan::New("Email").ToLocalChecked(),
         object
     );
  }

 
/*
  * @param Commit commit
   * @param EmailCreateOptions opts
    * @param Buf callback
   */
NAN_METHOD(GitEmail::CreateFromCommit) {

  if (info.Length() == 0 || !info[0]->IsObject()) {
    return Nan::ThrowError("Commit commit is required.");
  }

  if (info.Length() == 1 || !info[1]->IsObject()) {
    return Nan::ThrowError("EmailCreateOptions opts is required.");
  }

  if (!info[info.Length() - 1]->IsFunction()) {
    return Nan::ThrowError("Callback is required and must be a Function.");
  }

  CreateFromCommitBaton* baton = new CreateFromCommitBaton();

  baton->error_code = GIT_OK;
  baton->error = NULL;


  nodegit::Context *nodegitContext = reinterpret_cast<nodegit::Context *>(info.Data().As<External>()->Value());
  std::map<std::string, std::shared_ptr<nodegit::CleanupHandle>> cleanupHandles;

// start convert_from_v8 block
  git_commit * from_commit = NULL;
from_commit = Nan::ObjectWrap::Unwrap<GitCommit>(Nan::To<v8::Object>(info[0]).ToLocalChecked())->GetValue();
// end convert_from_v8 block
          baton->commit = from_commit;
            {
            auto conversionResult = ConfigurableGitEmailCreateOptions::fromJavascript(nodegitContext, info[1]);
            if (!conversionResult.result) {
              return Nan::ThrowError(Nan::New(conversionResult.error).ToLocalChecked());
            }

            auto convertedObject = conversionResult.result;
            cleanupHandles["opts"] = convertedObject;
            baton->opts = convertedObject->GetValue();
          }
 
  Nan::Callback *callback = new Nan::Callback(v8::Local<Function>::Cast(info[info.Length() - 1]));
  CreateFromCommitWorker *worker = new CreateFromCommitWorker(baton, callback, cleanupHandles);

             worker->Reference<GitCommit>("commit", info[0]);
             worker->Reference("opts", info[1]);
 
  nodegitContext->QueueWorker(worker);
  return;
}

nodegit::LockMaster GitEmail::CreateFromCommitWorker::AcquireLocks() {
  nodegit::LockMaster lockMaster(
    /*asyncAction: */true
          ,baton->out
          ,baton->commit
          ,baton->opts
  );

  return lockMaster;
}

void GitEmail::CreateFromCommitWorker::Execute() {
  git_error_clear();

    int result = git_email_create_from_commit(
baton->out,baton->commit,baton->opts  );

      baton->error_code = result;

      if (result != GIT_OK && git_error_last()->klass != GIT_ERROR_NONE) {
        baton->error = git_error_dup(git_error_last());
      }

}

void GitEmail::CreateFromCommitWorker::HandleErrorCallback() {
  if (!GetIsCancelled()) {
    v8::Local<v8::Object> err = Nan::To<v8::Object>(Nan::Error(ErrorMessage())).ToLocalChecked();
    Nan::Set(err, Nan::New("errorFunction").ToLocalChecked(), Nan::New("Email.createFromCommit").ToLocalChecked());
    v8::Local<v8::Value> argv[1] = {
      err
    };
    callback->Call(1, argv, async_resource);
  }

  if (baton->error) {
    if (baton->error->message) {
      free((void *)baton->error->message);
    }

    free((void *)baton->error);
  }

        git_buf_dispose(baton->out);
        free((void *)baton->out);

  delete baton;
}

void GitEmail::CreateFromCommitWorker::HandleOKCallback() {
    if (baton->error_code == GIT_OK) {
    v8::Local<v8::Value> v8ConversionSlot;
// start convert_to_v8 block
   if (baton->out) {
    v8ConversionSlot = Nan::New<v8::String>(baton->out->ptr, baton->out->size).ToLocalChecked();
  }
  else {
    v8ConversionSlot = Nan::Null();
  }
  // end convert_to_v8 block
      v8::Local<v8::Value> result = v8ConversionSlot;
        
    v8::Local<v8::Value> argv[2] = {
      Nan::Null(),
      result
    };
    callback->Call(2, argv, async_resource);
  } else {
    if (baton->error) {
      v8::Local<v8::Object> err;
      if (baton->error->message) {
        err = Nan::To<v8::Object>(Nan::Error(baton->error->message)).ToLocalChecked();
      } else {
        err = Nan::To<v8::Object>(Nan::Error("Method createFromCommit has thrown an error.")).ToLocalChecked();
      }
      Nan::Set(err, Nan::New("errno").ToLocalChecked(), Nan::New(baton->error_code));
      Nan::Set(err, Nan::New("errorFunction").ToLocalChecked(), Nan::New("Email.createFromCommit").ToLocalChecked());
      v8::Local<v8::Value> argv[1] = {
        err
      };
      callback->Call(1, argv, async_resource);
      if (baton->error->message)
        free((void *)baton->error->message);
      free((void *)baton->error);
    } else if (baton->error_code < 0) {
      bool callbackFired = false;
      if (!callbackErrorHandle.IsEmpty()) {
        v8::Local<v8::Value> maybeError = Nan::New(callbackErrorHandle);
        if (!maybeError->IsNull() && !maybeError->IsUndefined()) {
          v8::Local<v8::Value> argv[1] = {
            maybeError
          };
          callback->Call(1, argv, async_resource);
          callbackFired = true;
        }
      }

      if (!callbackFired) {
        v8::Local<v8::Object> err = Nan::To<v8::Object>(Nan::Error("Method createFromCommit has thrown an error.")).ToLocalChecked();
        Nan::Set(err, Nan::New("errno").ToLocalChecked(), Nan::New(baton->error_code));
        Nan::Set(err, Nan::New("errorFunction").ToLocalChecked(), Nan::New("Email.createFromCommit").ToLocalChecked());
        v8::Local<v8::Value> argv[1] = {
          err
        };
        callback->Call(1, argv, async_resource);
      }
    } else {
      callback->Call(0, NULL, async_resource);
    }

  }

        git_buf_dispose(baton->out);
        free((void *)baton->out);

  delete baton;
}

  
/*
  * @param Diff diff
   * @param Number patch_idx
   * @param Number patch_count
   * @param Oid commit_id
   * @param String summary
   * @param String body
   * @param Signature author
   * @param EmailCreateOptions opts
    * @param Buf callback
   */
NAN_METHOD(GitEmail::CreateFromDiff) {

  if (info.Length() == 0 || !info[0]->IsObject()) {
    return Nan::ThrowError("Diff diff is required.");
  }

  if (info.Length() == 1 || !info[1]->IsNumber()) {
    return Nan::ThrowError("Number patch_idx is required.");
  }

  if (info.Length() == 2 || !info[2]->IsNumber()) {
    return Nan::ThrowError("Number patch_count is required.");
  }

  if (info.Length() == 3
    || (!info[3]->IsObject() && !info[3]->IsString())) {
    return Nan::ThrowError("Oid commit_id is required.");
  }
  if (info.Length() == 4 || !info[4]->IsString()) {
    return Nan::ThrowError("String summary is required.");
  }

  if (info.Length() == 5 || !info[5]->IsString()) {
    return Nan::ThrowError("String body is required.");
  }

  if (info.Length() == 6 || !info[6]->IsObject()) {
    return Nan::ThrowError("Signature author is required.");
  }

  if (info.Length() == 7 || !info[7]->IsObject()) {
    return Nan::ThrowError("EmailCreateOptions opts is required.");
  }

  if (!info[info.Length() - 1]->IsFunction()) {
    return Nan::ThrowError("Callback is required and must be a Function.");
  }

  CreateFromDiffBaton* baton = new CreateFromDiffBaton();

  baton->error_code = GIT_OK;
  baton->error = NULL;


  nodegit::Context *nodegitContext = reinterpret_cast<nodegit::Context *>(info.Data().As<External>()->Value());
  std::map<std::string, std::shared_ptr<nodegit::CleanupHandle>> cleanupHandles;

// start convert_from_v8 block
  git_diff * from_diff = NULL;
from_diff = Nan::ObjectWrap::Unwrap<GitDiff>(Nan::To<v8::Object>(info[0]).ToLocalChecked())->GetValue();
// end convert_from_v8 block
          baton->diff = from_diff;
// start convert_from_v8 block
  size_t from_patch_idx;
      from_patch_idx = (size_t)   info[1].As<v8::Number>()->Value();
// end convert_from_v8 block
          baton->patch_idx = from_patch_idx;
// start convert_from_v8 block
  size_t from_patch_count;
      from_patch_count = (size_t)   info[2].As<v8::Number>()->Value();
// end convert_from_v8 block
          baton->patch_count = from_patch_count;
// start convert_from_v8 block
  const git_oid * from_commit_id = NULL;
  if (info[3]->IsString()) {
    // Try and parse in a string to a git_oid
    Nan::Utf8String oidString(Nan::To<v8::String>(info[3]).ToLocalChecked());
    git_oid *oidOut = (git_oid *)malloc(sizeof(git_oid));

    if (git_oid_fromstr(oidOut, (const char *) strdup(*oidString)) != GIT_OK) {
      free(oidOut);

      if (git_error_last()->klass != GIT_ERROR_NONE) {
        return Nan::ThrowError(git_error_last()->message);
      } else {
        return Nan::ThrowError("Unknown Error");
      }
    }

    from_commit_id = oidOut;
  }
  else {
from_commit_id = Nan::ObjectWrap::Unwrap<GitOid>(Nan::To<v8::Object>(info[3]).ToLocalChecked())->GetValue();
  }
// end convert_from_v8 block
          baton->commit_id = from_commit_id;
            baton->commit_idNeedsFree = info[3]->IsString();
// start convert_from_v8 block
  const char * from_summary = NULL;

  Nan::Utf8String summary(Nan::To<v8::String>(info[4]).ToLocalChecked());
  // malloc with one extra byte so we can add the terminating null character C-strings expect:
  from_summary = (const char *) malloc(summary.length() + 1);
  // copy the characters from the nodejs string into our C-string (used instead of strdup or strcpy because nulls in
  // the middle of strings are valid coming from nodejs):
  memcpy((void *)from_summary, *summary, summary.length());
  // ensure the final byte of our new string is null, extra casts added to ensure compatibility with various C types
  // used in the nodejs binding generation:
  memset((void *)(((char *)from_summary) + summary.length()), 0, 1);
// end convert_from_v8 block
          baton->summary = from_summary;
// start convert_from_v8 block
  const char * from_body = NULL;

  Nan::Utf8String body(Nan::To<v8::String>(info[5]).ToLocalChecked());
  // malloc with one extra byte so we can add the terminating null character C-strings expect:
  from_body = (const char *) malloc(body.length() + 1);
  // copy the characters from the nodejs string into our C-string (used instead of strdup or strcpy because nulls in
  // the middle of strings are valid coming from nodejs):
  memcpy((void *)from_body, *body, body.length());
  // ensure the final byte of our new string is null, extra casts added to ensure compatibility with various C types
  // used in the nodejs binding generation:
  memset((void *)(((char *)from_body) + body.length()), 0, 1);
// end convert_from_v8 block
          baton->body = from_body;
// start convert_from_v8 block
  const git_signature * from_author = NULL;
from_author = Nan::ObjectWrap::Unwrap<GitSignature>(Nan::To<v8::Object>(info[6]).ToLocalChecked())->GetValue();
// end convert_from_v8 block
          baton->author = from_author;
            {
            auto conversionResult = ConfigurableGitEmailCreateOptions::fromJavascript(nodegitContext, info[7]);
            if (!conversionResult.result) {
              return Nan::ThrowError(Nan::New(conversionResult.error).ToLocalChecked());
            }

            auto convertedObject = conversionResult.result;
            cleanupHandles["opts"] = convertedObject;
            baton->opts = convertedObject->GetValue();
          }
 
  Nan::Callback *callback = new Nan::Callback(v8::Local<Function>::Cast(info[info.Length() - 1]));
  CreateFromDiffWorker *worker = new CreateFromDiffWorker(baton, callback, cleanupHandles);

             worker->Reference<GitDiff>("diff", info[0]);
             worker->Reference("patch_idx", info[1]);
            worker->Reference("patch_count", info[2]);
              worker->Reference<GitOid>("commit_id", info[3]);
             worker->Reference("summary", info[4]);
            worker->Reference("body", info[5]);
              worker->Reference<GitSignature>("author", info[6]);
             worker->Reference("opts", info[7]);
 
  nodegitContext->QueueWorker(worker);
  return;
}

nodegit::LockMaster GitEmail::CreateFromDiffWorker::AcquireLocks() {
  nodegit::LockMaster lockMaster(
    /*asyncAction: */true
          ,baton->out
          ,baton->diff
          ,baton->commit_id
          ,baton->summary
          ,baton->body
          ,baton->author
          ,baton->opts
  );

  return lockMaster;
}

void GitEmail::CreateFromDiffWorker::Execute() {
  git_error_clear();

    int result = git_email_create_from_diff(
baton->out,baton->diff,baton->patch_idx,baton->patch_count,baton->commit_id,baton->summary,baton->body,baton->author,baton->opts  );

      baton->error_code = result;

      if (result != GIT_OK && git_error_last()->klass != GIT_ERROR_NONE) {
        baton->error = git_error_dup(git_error_last());
      }

}

void GitEmail::CreateFromDiffWorker::HandleErrorCallback() {
  if (!GetIsCancelled()) {
    v8::Local<v8::Object> err = Nan::To<v8::Object>(Nan::Error(ErrorMessage())).ToLocalChecked();
    Nan::Set(err, Nan::New("errorFunction").ToLocalChecked(), Nan::New("Email.createFromDiff").ToLocalChecked());
    v8::Local<v8::Value> argv[1] = {
      err
    };
    callback->Call(1, argv, async_resource);
  }

  if (baton->error) {
    if (baton->error->message) {
      free((void *)baton->error->message);
    }

    free((void *)baton->error);
  }

        git_buf_dispose(baton->out);
        free((void *)baton->out);
      if (baton->commit_idNeedsFree) {
        baton->commit_idNeedsFree = false;
        free((void *)baton->commit_id);
      }

  delete baton;
}

void GitEmail::CreateFromDiffWorker::HandleOKCallback() {
    if (baton->error_code == GIT_OK) {
    v8::Local<v8::Value> v8ConversionSlot;
// start convert_to_v8 block
   if (baton->out) {
    v8ConversionSlot = Nan::New<v8::String>(baton->out->ptr, baton->out->size).ToLocalChecked();
  }
  else {
    v8ConversionSlot = Nan::Null();
  }
  // end convert_to_v8 block
      v8::Local<v8::Value> result = v8ConversionSlot;
                    
    v8::Local<v8::Value> argv[2] = {
      Nan::Null(),
      result
    };
    callback->Call(2, argv, async_resource);
  } else {
    if (baton->error) {
      v8::Local<v8::Object> err;
      if (baton->error->message) {
        err = Nan::To<v8::Object>(Nan::Error(baton->error->message)).ToLocalChecked();
      } else {
        err = Nan::To<v8::Object>(Nan::Error("Method createFromDiff has thrown an error.")).ToLocalChecked();
      }
      Nan::Set(err, Nan::New("errno").ToLocalChecked(), Nan::New(baton->error_code));
      Nan::Set(err, Nan::New("errorFunction").ToLocalChecked(), Nan::New("Email.createFromDiff").ToLocalChecked());
      v8::Local<v8::Value> argv[1] = {
        err
      };
      callback->Call(1, argv, async_resource);
      if (baton->error->message)
        free((void *)baton->error->message);
      free((void *)baton->error);
    } else if (baton->error_code < 0) {
      bool callbackFired = false;
      if (!callbackErrorHandle.IsEmpty()) {
        v8::Local<v8::Value> maybeError = Nan::New(callbackErrorHandle);
        if (!maybeError->IsNull() && !maybeError->IsUndefined()) {
          v8::Local<v8::Value> argv[1] = {
            maybeError
          };
          callback->Call(1, argv, async_resource);
          callbackFired = true;
        }
      }

      if (!callbackFired) {
        v8::Local<v8::Object> err = Nan::To<v8::Object>(Nan::Error("Method createFromDiff has thrown an error.")).ToLocalChecked();
        Nan::Set(err, Nan::New("errno").ToLocalChecked(), Nan::New(baton->error_code));
        Nan::Set(err, Nan::New("errorFunction").ToLocalChecked(), Nan::New("Email.createFromDiff").ToLocalChecked());
        v8::Local<v8::Value> argv[1] = {
          err
        };
        callback->Call(1, argv, async_resource);
      }
    } else {
      callback->Call(0, NULL, async_resource);
    }

  }

        git_buf_dispose(baton->out);
        free((void *)baton->out);
      if (baton->commit_idNeedsFree) {
        baton->commit_idNeedsFree = false;
        free((void *)baton->commit_id);
      }

  delete baton;
}

     