#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "elf-types.h"
#include <stdlib.h>

struct obj_elf_s
{
  FILE* fd;

  size_t n_sec;

  uintptr_t entry_point;
};

void append(int src, int dst, int size, int offset)
{
  int i;
  char buf;
  int nb;

  int new_size;

  lseek(dst, offset, SEEK_SET);
  for (i=0;i<size;i++)
  {
    nb=read(src, &buf, 1);
    nb=write(dst, &buf, 1);
  }

  new_size = 512-size%512;
  buf = 0;
  for (i=0;i<new_size;i++)
    nb=write(dst, &buf, 1); 

}

void my_write(int fd, const char *buf, long offset)
{
  int i;
  int byte;
  
  lseek(fd, offset, SEEK_SET);
  
  for (i=0;i<strlen(buf);i++)
  {
    write(fd, &buf[i], 1);
  }

  return;
}

int main(int argc, char** argv)
{
  const char name[]        = "Mutekh";
  int entry_point          = 0x7f019f34;
  int stack                = 0x80e00000;
  int b_addr               = 0x80000000;
  struct stat filestate;
  int size;
  
  const char *dst;
  const char *src;

  if (argc != 4)
  {
    printf("./makeKernel src dest elffile\n");
    return 1;
  }

  FILE* obj;
  struct obj_elf_s *elf;
  Elf32_Ehdr *elf_hdr;
  size_t v_read;

  elf = malloc(sizeof(struct obj_elf_s));
  obj = fopen(argv[3], "r");
  if (!obj)
  {
    printf("cannot open file %s\n", argv[3]);
    abort();
  }
  elf->fd = obj;
  
  elf_hdr = malloc(sizeof(Elf32_Ehdr));
  v_read = fread(elf_hdr, 1, sizeof(Elf32_Ehdr), obj);
  
  if (v_read != sizeof(Elf32_Ehdr))
  {
    printf("cannot read elf header of %s\n", argv[3]);
    abort();
  }

  free(elf_hdr);
  fclose(obj);

  entry_point = elf_hdr->e_entry;
  printf("%x\n", entry_point);

  src = argv[1];
  dst = argv[2];

  stat(src, &filestate);

  size = filestate.st_size;

  int byte_value = 0;
  int i;

  int fd;
  int fdsrc;
  fd = open(dst, O_CREAT|O_WRONLY|O_TRUNC, 0666);
  fdsrc = open(src, O_RDONLY);
  if (fd == -1 || fdsrc == -1)
    printf("error\n");

  for (i=0;i<512;i++)
    write(fd, &byte_value, 1); 

  my_write(fd, name, 0);
  lseek(fd, 64, SEEK_SET);
  write(fd, &entry_point, sizeof(unsigned int));
  lseek(fd, 64+sizeof(unsigned int), SEEK_SET);
  write(fd, &size, sizeof(unsigned int));
  lseek(fd, 64+2*sizeof(unsigned int), SEEK_SET);
  write(fd, &b_addr, sizeof(unsigned int));
  lseek(fd, 64+3*sizeof(unsigned int), SEEK_SET);
  write(fd, &stack, sizeof(unsigned int));


  append(fdsrc, fd, size, 512);

  close(fd);
  close(fdsrc);

  return 0;
}
