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

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

#include "../include/functions/copy.h"
#include "../include/diff.h"

#include "../include/diff.h"
#include "../include/delta.h"
#include "../include/repository.h"
#include "../include/tree.h"
#include "../include/index.h"
#include "../include/diff_options.h"
#include "../include/diff_options.h"
#include "../include/diff.h"
#include "../include/repository.h"
#include "../include/tree.h"
#include "../include/index.h"
#include "../include/commit.h"

using namespace v8;
using namespace node;

GitDiff::GitDiff(git_diff *raw) {
  this->raw = raw;
}

GitDiff::~GitDiff() {
    git_diff_free(this->raw);
  }

void GitDiff::Initialize(Handle<v8::Object> target) {
  NanScope();

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

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

              NODE_SET_METHOD(tpl, "treeToTree", TreeToTree);
                        NODE_SET_PROTOTYPE_METHOD(tpl, "numDeltas", NumDeltas);
                        NODE_SET_PROTOTYPE_METHOD(tpl, "getDelta", GetDelta);
            
  
  Local<Function> _constructor_template = tpl->GetFunction();
  NanAssignPersistent(constructor_template, _constructor_template);
  target->Set(NanNew<String>("Diff"), _constructor_template);
}

NAN_METHOD(GitDiff::New) {
  NanScope();

  if (args.Length() == 0 || !args[0]->IsExternal()) {
    return NanThrowError("git_diff is required.");
  }
  GitDiff* object = new GitDiff(static_cast<git_diff *>(Handle<External>::Cast(args[0])->Value()));
  object->Wrap(args.This());

  NanReturnValue(args.This());
}

Handle<Value> GitDiff::New(void *raw) {
  NanEscapableScope();
  Handle<Value> argv[1] = { NanNew<External>((void *)raw) };
  return NanEscapeScope(NanNew<Function>(GitDiff::constructor_template)->NewInstance(1, argv));
}

git_diff *GitDiff::GetValue() {
  return this->raw;
}

            /**
        * @param Repository repo
            * @param Tree old_tree
            * @param Tree new_tree
            * @param DiffOptions opts
            * @param Diff callback
  */
NAN_METHOD(GitDiff::TreeToTree) {
  NanScope();
              if (args.Length() == 0 || !args[0]->IsObject()) {
      return NanThrowError("Repository repo is required.");
    }
                if (args.Length() == 1 || !args[1]->IsObject()) {
      return NanThrowError("Tree old_tree is required.");
    }
                if (args.Length() == 2 || !args[2]->IsObject()) {
      return NanThrowError("Tree new_tree is required.");
    }
              
  if (args.Length() == 4 || !args[4]->IsFunction()) {
    return NanThrowError("Callback is required and must be a Function.");
  }

  TreeToTreeBaton* baton = new TreeToTreeBaton;
  baton->error_code = GIT_OK;
  baton->error = NULL;
                      git_repository * from_repo;
          from_repo = ObjectWrap::Unwrap<GitRepository>(args[0]->ToObject())->GetValue();
  
            baton->repo = from_repo;
                                  git_tree * from_old_tree;
          from_old_tree = ObjectWrap::Unwrap<GitTree>(args[1]->ToObject())->GetValue();
  
            baton->old_tree = from_old_tree;
                                  git_tree * from_new_tree;
          from_new_tree = ObjectWrap::Unwrap<GitTree>(args[2]->ToObject())->GetValue();
  
            baton->new_tree = from_new_tree;
                                  const git_diff_options * from_opts;
      if (args[3]->IsObject()) {
          from_opts = ObjectWrap::Unwrap<GitDiffOptions>(args[3]->ToObject())->GetValue();
  
      } else {
      from_opts = 0;
    }
            baton->opts = from_opts;
                    
  NanCallback *callback = new NanCallback(Local<Function>::Cast(args[4]));
  TreeToTreeWorker *worker = new TreeToTreeWorker(baton, callback);
                    if (!args[0]->IsUndefined() && !args[0]->IsNull())
    worker->SaveToPersistent("repo", args[0]->ToObject());
                        if (!args[1]->IsUndefined() && !args[1]->IsNull())
    worker->SaveToPersistent("old_tree", args[1]->ToObject());
                        if (!args[2]->IsUndefined() && !args[2]->IsNull())
    worker->SaveToPersistent("new_tree", args[2]->ToObject());
                        if (!args[3]->IsUndefined() && !args[3]->IsNull())
    worker->SaveToPersistent("opts", args[3]->ToObject());
            
  NanAsyncQueueWorker(worker);
  NanReturnUndefined();
}

void GitDiff::TreeToTreeWorker::Execute() {
    int result = git_diff_tree_to_tree(
                    &baton->diff,    
              baton->repo,    
              baton->old_tree,    
              baton->new_tree,    
              baton->opts    
        );

    baton->error_code = result;

  if (result != GIT_OK && giterr_last() != NULL) {
    baton->error = git_error_dup(giterr_last());
  }

  }

void GitDiff::TreeToTreeWorker::HandleOKCallback() {
  TryCatch try_catch;
  if (baton->error_code == GIT_OK) {
        Handle<Value> to;
                      if (baton->diff != NULL) {
  to = GitDiff::New((void *)baton->diff);
} else {
  to = NanNull();
}
                        Handle<Value> result = to;
              Handle<Value> argv[2] = {
      NanNull(),
      result
    };
    callback->Call(2, argv);
  } else {
    if (baton->error) {
      Handle<Value> argv[1] = {
        NanError(baton->error->message)
      };
      callback->Call(1, argv);
      if (baton->error->message)
        free((void *)baton->error->message);
      free((void *)baton->error);
    } else {
      callback->Call(0, NULL);
    }

                                                        }

  if (try_catch.HasCaught()) {
    node::FatalException(try_catch);
  }

                                
  delete baton;
}
                  /**
              * @return Number result  */
NAN_METHOD(GitDiff::NumDeltas) {
  NanScope();
    
  
        
  size_t result = git_diff_num_deltas(
          ObjectWrap::Unwrap<GitDiff>(args.This())->GetValue()
            );

  

  Handle<Value> to;
          to = NanNew<Uint32>((uint32_t)result);
            NanReturnValue(to);
  }
                  /**
              * @param Number idx
            * @return Delta result  */
NAN_METHOD(GitDiff::GetDelta) {
  NanScope();
              if (args.Length() == 0 || !args[0]->IsUint32()) {
      return NanThrowError("Number idx is required.");
    }
      
  
                            size_t from_idx;
          from_idx = (size_t)   args[0]->ToUint32()->Value();
  
              
  const git_diff_delta * result = git_diff_get_delta(
          ObjectWrap::Unwrap<GitDiff>(args.This())->GetValue()
        ,          from_idx
            );

    

  Handle<Value> to;
          if (result != NULL) {
  result = (const git_diff_delta * )git_diff_delta_dup(result);
}
  if (result != NULL) {
  to = GitDelta::New((void *)result);
} else {
  to = NanNull();
}
          NanReturnValue(to);
  }
      

Persistent<Function> GitDiff::constructor_template;
