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

#include <node.h>
#include <v8.h>

#include <git2.h>
#include <map>
#include <algorithm>
#include <set>
#include <openssl/crypto.h>
#include <mutex>

#include "../include/init_ssh2.h"
#include "../include/lock_master.h"
#include "../include/nodegit.h"
#include "../include/context.h"
#include "../include/wrapper.h"
#include "../include/promise_completion.h"
#include "../include/functions/copy.h"
    #include "../include/annotated_commit.h"
     #include "../include/apply.h"
       #include "../include/apply_options.h"
     #include "../include/apply_options.h"
     #include "../include/attr.h"
      #include "../include/blame.h"
      #include "../include/blame_hunk.h"
     #include "../include/blame_options.h"
     #include "../include/blob.h"
      #include "../include/blob_filter_options.h"
     #include "../include/blob_filter_options.h"
     #include "../include/branch.h"
      #include "../include/branch_iterator.h"
     #include "../include/buf.h"
     #include "../include/cert.h"
      #include "../include/cert_hostkey.h"
       #include "../include/cert_x509.h"
     #include "../include/checkout.h"
      #include "../include/checkout_options.h"
     #include "../include/checkout_perfdata.h"
      #include "../include/cherrypick.h"
     #include "../include/cherrypick_options.h"
     #include "../include/clone.h"
      #include "../include/clone_options.h"
     #include "../include/commit.h"
     #include "../include/config.h"
     #include "../include/config_entry.h"
     #include "../include/config_entry.h"
     #include "../include/config_iterator.h"
      #include "../include/configmap.h"
      #include "../include/credential.h"
       #include "../include/describe_format_options.h"
     #include "../include/describe_format_options.h"
     #include "../include/describe_options.h"
     #include "../include/describe_options.h"
     #include "../include/describe_result.h"
     #include "../include/diff.h"
     #include "../include/diff_binary.h"
      #include "../include/diff_binary_file.h"
     #include "../include/diff_delta.h"
     #include "../include/diff_file.h"
      #include "../include/diff_find_options.h"
        #include "../include/diff_hunk.h"
     #include "../include/diff_line.h"
       #include "../include/diff_options.h"
     #include "../include/diff_patchid_options.h"
     #include "../include/diff_perfdata.h"
     #include "../include/diff_stats.h"
       #include "../include/error.h"
        #include "../include/fetch.h"
     #include "../include/fetch_options.h"
     #include "../include/fetch_options.h"
       #include "../include/filter.h"
     #include "../include/filter.h"
      #include "../include/filter_list.h"
      #include "../include/filter_source.h"
     #include "../include/graph.h"
     #include "../include/hashsig.h"
      #include "../include/ignore.h"
     #include "../include/index.h"
       #include "../include/index_conflict_iterator.h"
     #include "../include/index_entry.h"
       #include "../include/index_iterator.h"
     #include "../include/index_name_entry.h"
     #include "../include/index_reuc_entry.h"
      #include "../include/index_time.h"
     #include "../include/indexer_progress.h"
     #include "../include/libgit2.h"
      #include "../include/mailmap.h"
     #include "../include/merge.h"
        #include "../include/merge_file_input.h"
     #include "../include/merge_file_options.h"
     #include "../include/merge_file_result.h"
      #include "../include/merge_options.h"
      #include "../include/note.h"
     #include "../include/note_iterator.h"
     #include "../include/object.h"
      #include "../include/odb.h"
     #include "../include/odb_object.h"
      #include "../include/oid.h"
     #include "../include/oid_shorten.h"
     #include "../include/oidarray.h"
     #include "../include/packbuilder.h"
      #include "../include/patch.h"
     #include "../include/path.h"
       #include "../include/pathspec.h"
      #include "../include/pathspec_match_list.h"
     #include "../include/proxy.h"
      #include "../include/proxy_options.h"
     #include "../include/push_options.h"
     #include "../include/push_update.h"
     #include "../include/rebase.h"
     #include "../include/rebase_operation.h"
      #include "../include/rebase_options.h"
     #include "../include/rebase_options.h"
     #include "../include/refdb.h"
     #include "../include/reference.h"
       #include "../include/reflog.h"
     #include "../include/reflog_entry.h"
     #include "../include/refspec.h"
     #include "../include/remote.h"
      #include "../include/remote_callbacks.h"
     #include "../include/remote_callbacks.h"
       #include "../include/remote_create_options.h"
     #include "../include/remote_create_options.h"
     #include "../include/remote_head.h"
     #include "../include/remote_head.h"
     #include "../include/repository.h"
       #include "../include/repository_init_options.h"
        #include "../include/reset.h"
      #include "../include/revert.h"
     #include "../include/revert_options.h"
     #include "../include/revparse.h"
     #include "../include/revspec.h"
      #include "../include/revwalk.h"
     #include "../include/signature.h"
       #include "../include/stash.h"
      #include "../include/stash_apply_options.h"
     #include "../include/stash_apply_options.h"
       #include "../include/status.h"
      #include "../include/status_entry.h"
     #include "../include/status_list.h"
      #include "../include/status_options.h"
     #include "../include/status_options.h"
      #include "../include/strarray.h"
     #include "../include/submodule.h"
         #include "../include/submodule_update_options.h"
     #include "../include/tag.h"
     #include "../include/time.h"
     #include "../include/trace.h"
      #include "../include/transaction.h"
     #include "../include/transport.h"
     #include "../include/tree.h"
     #include "../include/tree_entry.h"
     #include "../include/tree_update.h"
      #include "../include/treebuilder.h"
      #include "../include/worktree.h"
     #include "../include/worktree_add_options.h"
     #include "../include/worktree_add_options.h"
      #include "../include/worktree_prune_options.h"
     #include "../include/worktree_prune_options.h"
     #include "../include/writestream.h"
  #include "../include/convenient_patch.h"
#include "../include/convenient_hunk.h"
#include "../include/filter_registry.h"

using namespace v8;

Local<Value> GetPrivate(Local<Object> object, Local<String> key) {
  Local<Value> value;
  Nan::Maybe<bool> result = Nan::HasPrivate(object, key);
  if (!(result.IsJust() && result.FromJust()))
    return Local<Value>();
  if (Nan::GetPrivate(object, key).ToLocal(&value))
    return value;
  return Local<Value>();
}

void SetPrivate(Local<Object> object, Local<String> key, Local<Value> value) {
  if (value.IsEmpty())
    return;
  Nan::SetPrivate(object, key, value);
}

static uv_mutex_t *opensslMutexes;

void OpenSSL_LockingCallback(int mode, int type, const char *, int) {
  if (mode & CRYPTO_LOCK) {
    uv_mutex_lock(&opensslMutexes[type]);
  } else {
    uv_mutex_unlock(&opensslMutexes[type]);
  }
}

void OpenSSL_IDCallback(CRYPTO_THREADID *id) {
  CRYPTO_THREADID_set_numeric(id, (unsigned long)uv_thread_self());
}

void OpenSSL_ThreadSetup() {
  opensslMutexes=(uv_mutex_t *)malloc(CRYPTO_num_locks() * sizeof(uv_mutex_t));

  for (int i=0; i<CRYPTO_num_locks(); i++) {
    uv_mutex_init(&opensslMutexes[i]);
  }

  CRYPTO_set_locking_callback(OpenSSL_LockingCallback);
  CRYPTO_THREADID_set_callback(OpenSSL_IDCallback);
}

// diagnostic function
NAN_METHOD(GetNumberOfTrackedObjects) {
  nodegit::Context *currentNodeGitContext = nodegit::Context::GetCurrentContext();
  assert (currentNodeGitContext != nullptr);
  info.GetReturnValue().Set(currentNodeGitContext->TrackerListSize());
}

static std::once_flag libraryInitializedFlag;
static std::mutex libraryInitializationMutex;

NAN_MODULE_INIT(init) {
  {
    // We only want to do initialization logic once, and we also want to prevent any thread from completely loading
    // the module until initialization has occurred.
    // All of this initialization logic ends up being shared.
    const std::lock_guard<std::mutex> lock(libraryInitializationMutex);
    std::call_once(libraryInitializedFlag, []() {
      // Initialize thread safety in openssl and libssh2
      OpenSSL_ThreadSetup();
      init_ssh2();
      // Initialize libgit2.
      git_libgit2_init();

      // Register thread pool with libgit2
      nodegit::ThreadPool::InitializeGlobal();
    });
  }

  // Exports function 'getNumberOfTrackedObjects'
  Nan::Set(target
    , Nan::New<v8::String>("getNumberOfTrackedObjects").ToLocalChecked()
    , Nan::GetFunction(Nan::New<v8::FunctionTemplate>(GetNumberOfTrackedObjects)).ToLocalChecked()
  );

  Nan::HandleScope scope;
  Local<Context> context = Nan::GetCurrentContext();
  Isolate *isolate = context->GetIsolate();
  nodegit::Context *nodegitContext = new nodegit::Context(isolate);

  Wrapper::InitializeComponent(target, nodegitContext);
  PromiseCompletion::InitializeComponent(nodegitContext);
      GitAnnotatedCommit::InitializeComponent(target, nodegitContext);
       GitApply::InitializeComponent(target, nodegitContext);
             GitAttr::InitializeComponent(target, nodegitContext);
        GitBlame::InitializeComponent(target, nodegitContext);
        GitBlameHunk::InitializeComponent(target, nodegitContext);
         GitBlob::InitializeComponent(target, nodegitContext);
            GitBranch::InitializeComponent(target, nodegitContext);
        GitBranchIterator::InitializeComponent(target, nodegitContext);
       GitBuf::InitializeComponent(target, nodegitContext);
       GitCert::InitializeComponent(target, nodegitContext);
        GitCertHostkey::InitializeComponent(target, nodegitContext);
         GitCertX509::InitializeComponent(target, nodegitContext);
       GitCheckout::InitializeComponent(target, nodegitContext);
          GitCheckoutPerfdata::InitializeComponent(target, nodegitContext);
        GitCherrypick::InitializeComponent(target, nodegitContext);
         GitClone::InitializeComponent(target, nodegitContext);
          GitCommit::InitializeComponent(target, nodegitContext);
       GitConfig::InitializeComponent(target, nodegitContext);
       GitConfigEntry::InitializeComponent(target, nodegitContext);
       GitConfigEntry::InitializeComponent(target, nodegitContext);
       GitConfigIterator::InitializeComponent(target, nodegitContext);
        GitConfigmap::InitializeComponent(target, nodegitContext);
        GitCredential::InitializeComponent(target, nodegitContext);
                 GitDescribeResult::InitializeComponent(target, nodegitContext);
       GitDiff::InitializeComponent(target, nodegitContext);
       GitDiffBinary::InitializeComponent(target, nodegitContext);
        GitDiffBinaryFile::InitializeComponent(target, nodegitContext);
       GitDiffDelta::InitializeComponent(target, nodegitContext);
       GitDiffFile::InitializeComponent(target, nodegitContext);
             GitDiffHunk::InitializeComponent(target, nodegitContext);
       GitDiffLine::InitializeComponent(target, nodegitContext);
             GitDiffPerfdata::InitializeComponent(target, nodegitContext);
       GitDiffStats::InitializeComponent(target, nodegitContext);
         GitError::InitializeComponent(target, nodegitContext);
          GitFetch::InitializeComponent(target, nodegitContext);
                  GitFilterList::InitializeComponent(target, nodegitContext);
        GitFilterSource::InitializeComponent(target, nodegitContext);
       GitGraph::InitializeComponent(target, nodegitContext);
       GitHashsig::InitializeComponent(target, nodegitContext);
        GitIgnore::InitializeComponent(target, nodegitContext);
       GitIndex::InitializeComponent(target, nodegitContext);
         GitIndexConflictIterator::InitializeComponent(target, nodegitContext);
       GitIndexEntry::InitializeComponent(target, nodegitContext);
          GitIndexIterator::InitializeComponent(target, nodegitContext);
       GitIndexNameEntry::InitializeComponent(target, nodegitContext);
       GitIndexReucEntry::InitializeComponent(target, nodegitContext);
        GitIndexTime::InitializeComponent(target, nodegitContext);
        GitIndexerProgress::InitializeComponent(target, nodegitContext);
       GitLibgit2::InitializeComponent(target, nodegitContext);
        GitMailmap::InitializeComponent(target, nodegitContext);
       GitMerge::InitializeComponent(target, nodegitContext);
              GitMergeFileResult::InitializeComponent(target, nodegitContext);
           GitNote::InitializeComponent(target, nodegitContext);
       GitNoteIterator::InitializeComponent(target, nodegitContext);
       GitObject::InitializeComponent(target, nodegitContext);
        GitOdb::InitializeComponent(target, nodegitContext);
       GitOdbObject::InitializeComponent(target, nodegitContext);
        GitOid::InitializeComponent(target, nodegitContext);
       GitOidShorten::InitializeComponent(target, nodegitContext);
       GitOidarray::InitializeComponent(target, nodegitContext);
       GitPackbuilder::InitializeComponent(target, nodegitContext);
        GitPatch::InitializeComponent(target, nodegitContext);
       GitPath::InitializeComponent(target, nodegitContext);
         GitPathspec::InitializeComponent(target, nodegitContext);
        GitPathspecMatchList::InitializeComponent(target, nodegitContext);
       GitProxy::InitializeComponent(target, nodegitContext);
            GitPushUpdate::InitializeComponent(target, nodegitContext);
       GitRebase::InitializeComponent(target, nodegitContext);
       GitRebaseOperation::InitializeComponent(target, nodegitContext);
            GitRefdb::InitializeComponent(target, nodegitContext);
       GitRefs::InitializeComponent(target, nodegitContext);
         GitReflog::InitializeComponent(target, nodegitContext);
       GitReflogEntry::InitializeComponent(target, nodegitContext);
       GitRefspec::InitializeComponent(target, nodegitContext);
       GitRemote::InitializeComponent(target, nodegitContext);
                  GitRemoteHead::InitializeComponent(target, nodegitContext);
       GitRemoteHead::InitializeComponent(target, nodegitContext);
       GitRepository::InitializeComponent(target, nodegitContext);
              GitReset::InitializeComponent(target, nodegitContext);
        GitRevert::InitializeComponent(target, nodegitContext);
         GitRevparse::InitializeComponent(target, nodegitContext);
       GitRevspec::InitializeComponent(target, nodegitContext);
        GitRevwalk::InitializeComponent(target, nodegitContext);
       GitSignature::InitializeComponent(target, nodegitContext);
         GitStash::InitializeComponent(target, nodegitContext);
              GitStatus::InitializeComponent(target, nodegitContext);
        GitStatusEntry::InitializeComponent(target, nodegitContext);
       GitStatusList::InitializeComponent(target, nodegitContext);
             GitStrarray::InitializeComponent(target, nodegitContext);
       GitSubmodule::InitializeComponent(target, nodegitContext);
             GitTag::InitializeComponent(target, nodegitContext);
       GitTime::InitializeComponent(target, nodegitContext);
       GitTrace::InitializeComponent(target, nodegitContext);
        GitTransaction::InitializeComponent(target, nodegitContext);
       GitTransport::InitializeComponent(target, nodegitContext);
       GitTree::InitializeComponent(target, nodegitContext);
       GitTreeEntry::InitializeComponent(target, nodegitContext);
          GitTreebuilder::InitializeComponent(target, nodegitContext);
        GitWorktree::InitializeComponent(target, nodegitContext);
                GitWritestream::InitializeComponent(target, nodegitContext);
  
  ConvenientHunk::InitializeComponent(target, nodegitContext);
  ConvenientPatch::InitializeComponent(target, nodegitContext);
  GitFilterRegistry::InitializeComponent(target, nodegitContext);

  nodegit::LockMaster::InitializeContext();
}

NAN_MODULE_WORKER_ENABLED(nodegit, init)
