// 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/commit.h"

#include "../include/signature.h"
#include "../include/commit.h"
#include "../include/repository.h"
#include "../include/tree.h"
#include "../include/oid.h"

using namespace v8;
using namespace node;

GitCommit::GitCommit(git_commit *raw) {
  this->raw = raw;
}

GitCommit::~GitCommit() {
    git_commit_free(this->raw);
  }

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

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

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

              NODE_SET_METHOD(tpl, "lookup", Lookup);
                        NODE_SET_PROTOTYPE_METHOD(tpl, "id", Id);
                        NODE_SET_PROTOTYPE_METHOD(tpl, "message", Message);
                        NODE_SET_PROTOTYPE_METHOD(tpl, "time", Time);
                        NODE_SET_PROTOTYPE_METHOD(tpl, "timeOffset", TimeOffset);
                        NODE_SET_PROTOTYPE_METHOD(tpl, "committer", Committer);
                        NODE_SET_PROTOTYPE_METHOD(tpl, "author", Author);
                        NODE_SET_PROTOTYPE_METHOD(tpl, "treeId", TreeId);
                        NODE_SET_PROTOTYPE_METHOD(tpl, "parentcount", Parentcount);
                        NODE_SET_PROTOTYPE_METHOD(tpl, "parentId", ParentId);
                        NODE_SET_METHOD(tpl, "createCommit", CreateCommit);
            
  
  Local<Function> _constructor_template = tpl->GetFunction();
  NanAssignPersistent(constructor_template, _constructor_template);
  target->Set(NanNew<String>("Commit"), _constructor_template);
}

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

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

  NanReturnValue(args.This());
}

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

git_commit *GitCommit::GetValue() {
  return this->raw;
}

            /**
        * @param Repository repo
            * @param Oid id
            * @param Commit callback
  */
NAN_METHOD(GitCommit::Lookup) {
  NanScope();
              if (args.Length() == 0 || !args[0]->IsObject()) {
      return NanThrowError("Repository repo is required.");
    }
                if (args.Length() == 1 || !args[1]->IsObject()) {
      return NanThrowError("Oid id is required.");
    }
      
  if (args.Length() == 2 || !args[2]->IsFunction()) {
    return NanThrowError("Callback is required and must be a Function.");
  }

  LookupBaton* baton = new LookupBaton;
  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;
                                  const git_oid * from_id;
          from_id = ObjectWrap::Unwrap<GitOid>(args[1]->ToObject())->GetValue();
  
            baton->id = from_id;
                    
  NanCallback *callback = new NanCallback(Local<Function>::Cast(args[2]));
  LookupWorker *worker = new LookupWorker(baton, callback);
                    if (!args[0]->IsUndefined() && !args[0]->IsNull())
    worker->SaveToPersistent("repo", args[0]->ToObject());
                        if (!args[1]->IsUndefined() && !args[1]->IsNull())
    worker->SaveToPersistent("id", args[1]->ToObject());
            
  NanAsyncQueueWorker(worker);
  NanReturnUndefined();
}

void GitCommit::LookupWorker::Execute() {
    int result = git_commit_lookup(
                    &baton->commit,    
              baton->repo,    
              baton->id    
        );

    baton->error_code = result;

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

  }

void GitCommit::LookupWorker::HandleOKCallback() {
  TryCatch try_catch;
  if (baton->error_code == GIT_OK) {
        Handle<Value> to;
                      if (baton->commit != NULL) {
  to = GitCommit::New((void *)baton->commit);
} 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);
    }

                        free(baton->repo);
                      }

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

                    
  delete baton;
}
                  /**
              * @return Oid result  */
NAN_METHOD(GitCommit::Id) {
  NanScope();
    
  
        
  const git_oid * result = git_commit_id(
          ObjectWrap::Unwrap<GitCommit>(args.This())->GetValue()
            );

  

  Handle<Value> to;
          if (result != NULL) {
  to = GitOid::New((void *)result);
} else {
  to = NanNull();
}
          NanReturnValue(to);
  }
                  /**
              * @return String result  */
NAN_METHOD(GitCommit::Message) {
  NanScope();
    
  
        
  const char * result = git_commit_message(
          ObjectWrap::Unwrap<GitCommit>(args.This())->GetValue()
            );

  

  Handle<Value> to;
          to = NanNew<String>(result);
  
            NanReturnValue(to);
  }
                  /**
              * @return Number result  */
NAN_METHOD(GitCommit::Time) {
  NanScope();
    
  
        
  git_time_t result = git_commit_time(
          ObjectWrap::Unwrap<GitCommit>(args.This())->GetValue()
            );

  

  Handle<Value> to;
          to = NanNew<Int32>((int32_t)result);
            NanReturnValue(to);
  }
                  /**
              * @return Int32 result  */
NAN_METHOD(GitCommit::TimeOffset) {
  NanScope();
    
  
        
  int result = git_commit_time_offset(
          ObjectWrap::Unwrap<GitCommit>(args.This())->GetValue()
            );

  

  Handle<Value> to;
          to = NanNew<Number>(result);
            NanReturnValue(to);
  }
                  /**
              * @return Signature result  */
NAN_METHOD(GitCommit::Committer) {
  NanScope();
    
  
        
  const git_signature * result = git_commit_committer(
          ObjectWrap::Unwrap<GitCommit>(args.This())->GetValue()
            );

  

  Handle<Value> to;
          if (result != NULL) {
  to = GitSignature::New((void *)result);
} else {
  to = NanNull();
}
          NanReturnValue(to);
  }
                  /**
              * @return Signature result  */
NAN_METHOD(GitCommit::Author) {
  NanScope();
    
  
        
  const git_signature * result = git_commit_author(
          ObjectWrap::Unwrap<GitCommit>(args.This())->GetValue()
            );

  

  Handle<Value> to;
          if (result != NULL) {
  to = GitSignature::New((void *)result);
} else {
  to = NanNull();
}
          NanReturnValue(to);
  }
                  /**
              * @return Oid result  */
NAN_METHOD(GitCommit::TreeId) {
  NanScope();
    
  
        
  const git_oid * result = git_commit_tree_id(
          ObjectWrap::Unwrap<GitCommit>(args.This())->GetValue()
            );

  

  Handle<Value> to;
          if (result != NULL) {
  to = GitOid::New((void *)result);
} else {
  to = NanNull();
}
          NanReturnValue(to);
  }
                  /**
              * @return Uint32 result  */
NAN_METHOD(GitCommit::Parentcount) {
  NanScope();
    
  
        
  unsigned int result = git_commit_parentcount(
          ObjectWrap::Unwrap<GitCommit>(args.This())->GetValue()
            );

  

  Handle<Value> to;
          to = NanNew<Number>(result);
            NanReturnValue(to);
  }
                  /**
              * @param Uint32 n
            * @return Oid result  */
NAN_METHOD(GitCommit::ParentId) {
  NanScope();
              if (args.Length() == 0 || !args[0]->IsNumber()) {
      return NanThrowError("Uint32 n is required.");
    }
      
  
                            unsigned int from_n;
          from_n = (unsigned int)   args[0]->ToNumber()->Value();
  
              
  const git_oid * result = git_commit_parent_id(
          ObjectWrap::Unwrap<GitCommit>(args.This())->GetValue()
        ,          from_n
            );

    

  Handle<Value> to;
          if (result != NULL) {
  to = GitOid::New((void *)result);
} else {
  to = NanNull();
}
          NanReturnValue(to);
  }
                  /**
                * @param String update_ref
            * @param Signature author
            * @param Signature committer
            * @param String message_encoding
            * @param String message
            * @param Tree tree
            * @param Number parent_count
            * @param Array parents
            * @param Oid callback
  */
NAN_METHOD(GitCommit::CreateCommit) {
  NanScope();
                        if (args.Length() == 1 || !args[1]->IsObject()) {
      return NanThrowError("Signature author is required.");
    }
                if (args.Length() == 2 || !args[2]->IsObject()) {
      return NanThrowError("Signature committer is required.");
    }
                        if (args.Length() == 4 || !args[4]->IsString()) {
      return NanThrowError("String message is required.");
    }
                if (args.Length() == 5 || !args[5]->IsObject()) {
      return NanThrowError("Tree tree is required.");
    }
                if (args.Length() == 6 || !args[6]->IsUint32()) {
      return NanThrowError("Number parent_count is required.");
    }
                if (args.Length() == 7 || !args[7]->IsObject()) {
      return NanThrowError("Array parents is required.");
    }
      
  if (args.Length() == 8 || !args[8]->IsFunction()) {
    return NanThrowError("Callback is required and must be a Function.");
  }

  CreateCommitBaton* baton = new CreateCommitBaton;
  baton->error_code = GIT_OK;
  baton->error = NULL;
        baton->id = (git_oid *)malloc(sizeof(git_oid ));
                  baton->repo = ObjectWrap::Unwrap<GitRepository>(args.This())->GetValue();
                          const char * from_update_ref;
      if (args[0]->IsString()) {
          String::Utf8Value update_ref(args[0]->ToString());
      from_update_ref = (const char *) strdup(*update_ref);
  
      } else {
      from_update_ref = 0;
    }
            baton->update_ref = from_update_ref;
                                  const git_signature * from_author;
          from_author = ObjectWrap::Unwrap<GitSignature>(args[1]->ToObject())->GetValue();
  
            baton->author = from_author;
                                  const git_signature * from_committer;
          from_committer = ObjectWrap::Unwrap<GitSignature>(args[2]->ToObject())->GetValue();
  
            baton->committer = from_committer;
                                  const char * from_message_encoding;
      if (args[3]->IsString()) {
          String::Utf8Value message_encoding(args[3]->ToString());
      from_message_encoding = (const char *) strdup(*message_encoding);
  
      } else {
      from_message_encoding = 0;
    }
            baton->message_encoding = from_message_encoding;
                                  const char * from_message;
          String::Utf8Value message(args[4]->ToString());
      from_message = (const char *) strdup(*message);
  
            baton->message = from_message;
                                  const git_tree * from_tree;
          from_tree = ObjectWrap::Unwrap<GitTree>(args[5]->ToObject())->GetValue();
  
            baton->tree = from_tree;
                                  size_t from_parent_count;
          from_parent_count = (size_t)   args[6]->ToUint32()->Value();
  
            baton->parent_count = from_parent_count;
                                  const git_commit ** from_parents;
          Array *tmp_parents = Array::Cast(*args[7]);
      from_parents = (const git_commit **)malloc(tmp_parents->Length() * sizeof(const git_commit *));
      for (unsigned int i = 0; i < tmp_parents->Length(); i++) {
            from_parents[i] = ObjectWrap::Unwrap<GitCommit>(tmp_parents->Get(NanNew<Number>(static_cast<double>(i)))->ToObject())->GetValue();
      }
  
            baton->parents = from_parents;
                    
  NanCallback *callback = new NanCallback(Local<Function>::Cast(args[8]));
  CreateCommitWorker *worker = new CreateCommitWorker(baton, callback);
                    worker->SaveToPersistent("repo", args.This());
                        if (!args[0]->IsUndefined() && !args[0]->IsNull())
    worker->SaveToPersistent("update_ref", args[0]->ToObject());
                        if (!args[1]->IsUndefined() && !args[1]->IsNull())
    worker->SaveToPersistent("author", args[1]->ToObject());
                        if (!args[2]->IsUndefined() && !args[2]->IsNull())
    worker->SaveToPersistent("committer", args[2]->ToObject());
                        if (!args[3]->IsUndefined() && !args[3]->IsNull())
    worker->SaveToPersistent("message_encoding", args[3]->ToObject());
                        if (!args[4]->IsUndefined() && !args[4]->IsNull())
    worker->SaveToPersistent("message", args[4]->ToObject());
                        if (!args[5]->IsUndefined() && !args[5]->IsNull())
    worker->SaveToPersistent("tree", args[5]->ToObject());
                        if (!args[6]->IsUndefined() && !args[6]->IsNull())
    worker->SaveToPersistent("parent_count", args[6]->ToObject());
                        if (!args[7]->IsUndefined() && !args[7]->IsNull())
    worker->SaveToPersistent("parents", args[7]->ToObject());
            
  NanAsyncQueueWorker(worker);
  NanReturnUndefined();
}

void GitCommit::CreateCommitWorker::Execute() {
    int result = git_commit_create(
                    baton->id,    
              baton->repo,    
              baton->update_ref,    
              baton->author,    
              baton->committer,    
              baton->message_encoding,    
              baton->message,    
              baton->tree,    
              baton->parent_count,    
              baton->parents    
        );

    baton->error_code = result;

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

  }

void GitCommit::CreateCommitWorker::HandleOKCallback() {
  TryCatch try_catch;
  if (baton->error_code == GIT_OK) {
        Handle<Value> to;
                      if (baton->id != NULL) {
  to = GitOid::New((void *)baton->id);
} 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);
    }

              free(baton->id);
                                                                                                      }

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

                          free((void *)baton->update_ref);
                                    free((void *)baton->message_encoding);
                        free((void *)baton->message);
                                    free((void *)baton->parents);
            
  delete baton;
}
      

Persistent<Function> GitCommit::constructor_template;
