#include <stdint.h>
#include <string.h>
#include <string>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include "crypto.h"
#include "SealerWrapper.h"

#include "DeploymentStageLogic.h"
using namespace std;

#define DECRYPTOR_PORT 3824
#define SGX_HASH_SIZE 32
int __ImageBase=0;
int verify_apache(std::string& path, std::string& keypair) {return 0; }

void foo() //sigsegv_handler(int signo)
{
	printf("foo hehe ---------------------\n"); 
	fflush(stdout); 
}





int main(int argc, char** argv)
{

//	signal(SIGSEGV, SIG_IGN);  //sigsegv_handler); 
/*	
    JavaVM         *vm;
    JNIEnv         *env;
    JavaVMInitArgs  vm_args;
    jint            res;
    jclass          cls;
    jmethodID       mid;
    jstring         jstr;
    jobjectArray    main_args;
    JavaVMOption* options = new JavaVMOption[7];
    options[0].optionString = "-Dpixy.home=/home/m2mazmud/pixy-master";
    options[1].optionString = "-Djava.class.path=/home/m2mazmud/pixy-master/lib:/home/m2mazmud/pixy-master/build/class";
    options[2].optionString = "-Xcheck:jni";
    options[3].optionString = "-Xms32m";
    options[4].optionString = "-Xmx128m";
    options[5].optionString = "-XX:MaxMetaspaceSize=128m"; 
    options[6].optionString = "-Xss256k"; 
    vm_args.options            = options;
    vm_args.nOptions           = 7;

	printf("Helloworld\n"); fflush(stdout);
    vm_args.ignoreUnrecognized = JNI_TRUE;
    vm_args.version  = JNI_VERSION_1_8;
//	sleep(60); 
    if (JNI_CreateJavaVM(&vm, (void **)&env, &vm_args) != JNI_OK) {
        delete options;
	printf("Failed to create Java VMn");
        return 1;
    }
	printf("WOO HOO CREATED JVM\n");  fflush(stdout); 
	delete options; 
    cls = (env)->FindClass("at/ac/tuwien/infosys/www/pixy/Checker");
    if (cls == NULL) {
        printf("Failed to find Main classn");
        return 1;
    }

    mid = (env)->GetStaticMethodID(cls, "main", "([Ljava/lang/String;)V");
    if (mid == NULL) {
        printf("Failed to find main functionnnnn");
        return 1;
    }
    printf("Hehehehe\n"); fflush(stdout);

    jclass classString = (env)->FindClass("java/lang/String");
    jstr      = (env)->NewStringUTF("");
    main_args = (env)->NewObjectArray( 8, classString, jstr);

    (env)->SetObjectArrayElement( main_args, 0, (env)->NewStringUTF( "-aAvLf"));
    (env)->SetObjectArrayElement( main_args, 1, (env)->NewStringUTF( "-s"));
    (env)->SetObjectArrayElement( main_args, 2, (env)->NewStringUTF( "/home/m2mazmud/pixy-master/config/sinks_xss.txt"));
    (env)->SetObjectArrayElement( main_args, 3, (env)->NewStringUTF( "-o"));
    (env)->SetObjectArrayElement( main_args, 4, (env)->NewStringUTF( "/home/m2mazmud/pixy-master/sample_mitigator/results"));
    (env)->SetObjectArrayElement( main_args, 5, (env)->NewStringUTF( "-y"));
    (env)->SetObjectArrayElement( main_args, 6, (env)->NewStringUTF( "xss"));
    if(argc>=1)
      (env)->SetObjectArrayElement( main_args, 7, (env)->NewStringUTF( argv[1]));

    (env)->CallStaticVoidMethod( cls, mid, main_args);
    if((env)->ExceptionOccurred()) {
	(env)->ExceptionDescribe();
      (env)->ExceptionClear();
      printf("Exception occurred\n"); fflush(stdout);
    }

/*
  printf("HELLOWORLD\n");fflush(stdout); 
//  Py_SetProgramName("verifier");  
  printf("HELLOWORLD 2\n"); fflush(stdout); 
  Py_Initialize();
  printf("HELLOWORLD 3\n");fflush(stdout); 

  PyRun_SimpleString("from time import time,ctime\n"
                     "print 'Today is',ctime(time())\n");
  Py_Finalize();
//  return 0;

*/

    /*
  // uint8_t expected_apache_mr_signer[32] = {0};
  std::string apache_signature_keypair_private("1234567890");
  std::string apache_public_key;
  std::string apache_private_key2; 
//  generate_rsa_keypair(apache_public_key, apache_private_key2); 
  uint32_t return_sgx; uint32_t return_internal;
  std::string recovered_plaintext;
  uint32_t expected_sealed_msg_size=0;

  FILE* fp = fopen("./apache_signature_keypair.pem", "w+");
  if(fp == NULL)
 {
	perror("Could not create the file ./apache_signature_keypair.pem due to error: "); fflush(stderr); return 0xffffffff;
  }
//  RSA_signing_keypair rsa_signing_keypair();
  return_internal = generate_rsa_keypair(fp, apache_public_key, apache_private_key2); //, expected_apache_mr_signer); 
  if(return_internal !=0)
  {
	printf("Could not generate RSA keypair - error 0x%x\n", return_internal); fflush(stdout); return return_internal; 
  }
  printf("Generated key pair - outside the fun\n"); fflush(stdout); 

  int sealed_file_fd = open("sealed_msg.txt", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
  if(sealed_file_fd == -1)
  {
    perror("\nError in opening or creating the file sealed_msg.txt - ");
    fflush(stderr);
    return 0xFFFFFFFF;
  }
  printf("\nSuccessfully opened a file to seal the apache signature keypair to.\n");
  fflush(stdout);

  return_sgx = seal_message_to_file(sealed_file_fd, apache_signature_keypair_private, &expected_sealed_msg_size);
  if(return_sgx!=0 && return_sgx!=0xFFFFFFFF)
  {
    printf("Sealing SGX error %x", return_sgx);
    fflush(stdout);
    return return_sgx;
  }
  else if(return_sgx == 0xFFFFFFFF)
  {
    perror("Successful SGX sealing, but error in writing to a file or write returned 0 bytes because the disk was full etc.\n");
    fflush(stdout);
    return return_sgx;
  }
  printf("\nSuccessfully sealed the plaintext %s to length 0x%x.\n", apache_signature_keypair_private.c_str(), expected_sealed_msg_size);
  fflush(stdout);
    */
    uint8_t target_hash[32] = {0x54,0x24,0x5d,0x63,0x5c,0x8f,0xec,0xcf,0x37,0xb9,0xcf,0x9e,0xb8,0xd3,0x22,0x04,0x57,0x5b,0xb2,0xfc,0xa6,0xd3,0x11,0xfb,0x87,0xb7,0x01,0x06,0x2f,0x18,0x25,0xc1};
    DeploymentStageLogic deploymentStage;

    deploymentStage.set_target_hash(target_hash);

    printf("Setting up SOCKET:\n"); fflush(stdout);
    int fd = deploymentStage.set_up_socket_connect(DECRYPTOR_PORT);
    if(fd <= 0)
        // Set up an IPC channel for local attestation and post-LA messages.
    {
        printf("\nCould not set up the socket: had the following error: %d\n", fd);
        fflush(stdout);
        return fd;
    }
    printf("Starting main logic with fd: %d\n", fd); fflush(stdout);

    int ret_status = deploymentStage.main_logic(fd);
    if(ret_status != 0)
        return ret_status;

/*
//  sleep(50);
  printf("\n z z z z z z  z z z z z z z  (sleeping for a bit) z z z z z  z z z (meant to emulate the '2nd' stage of validator, that will be rerun whenever Apache changes)\n");
  return_sgx = unseal_message_from_file(sealed_file_fd, recovered_plaintext, &expected_sealed_msg_size);
  if(return_sgx!=0 && return_sgx!=0xFFFFFFFF)
  {
    printf("Successful read from file, but error in SGX unsealing: %x.\n", return_sgx);
    fflush(stdout);
    return return_sgx;
  }
  else if(return_sgx == 0xFFFFFFFF)
  {
    perror("\n Could not read the file.\n");
    fflush(stdout);
    return return_sgx;
  }
  printf("\n Unsealed the keypair.\n");
  fflush(stdout);

  std::string path("../apache/source/code/path");
  return_internal = verify_apache(path, apache_signature_keypair_private);
  if(return_internal != 0)
  {
    printf("\nThe signed manifest was not created due to the above errors.\n");
    fflush(stdout);
    return return_internal;
  }
  printf("Successfully verified the Apache enclave and signed its manifest.\n");
  fflush(stdout);
*/
  return 0;


}
