#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "fdisk.h"

/* FIXME: strdup memory leaks on reread */

/* externs */
struct fdisk_disk *fdisk_disks = NULL;
struct fdisk_partition *fdisk_partitions[256];

/* internal state */
static struct fdisk_disk *last_disk;
static struct fdisk_partition *last_partition;
static struct fdisk_partition *last_partitions[255];


void fdisk_init() {
  int i;

  if (NULL == fdisk_disks) {
    /* free memory */;
  }

  for (i=0; i<=255; i++) {
    fdisk_partitions[i] = NULL;
    last_partitions[i] = NULL;
  }

  fdisk_disks = last_disk = NULL;
  last_partition = NULL;

}


struct fdisk_disk *
fdisk_add_disk( char *name, int size){
  struct fdisk_disk *disk;
  
  disk = (struct fdisk_disk *) malloc(sizeof(struct fdisk_disk));

  disk->name = strdup(name);
  disk->size = size;
  disk->next = NULL;
  disk->partitions = NULL;

  if (NULL == fdisk_disks) {
    fdisk_disks = disk;
  }

  if (NULL != last_disk) {
    last_disk->next = disk;
  }
  last_disk = disk;

  return(0);
}


struct fdisk_partition *
fdisk_add_partition(char *name, int type){

  struct fdisk_partition *partition;

  partition = (struct fdisk_partition *) 
    malloc(sizeof(struct fdisk_partition));

  partition->name= strdup(name);
  partition->type = type;
  partition->next_by_disk = NULL;
  partition->next_by_type = NULL;
  
  if (NULL == last_disk->partitions) {
    last_disk->partitions = partition;
    last_partition = NULL;
  }

  if (NULL != last_partition) {
    last_partition->next_by_disk = partition;
  }
  last_partition = partition;


  if (NULL == fdisk_partitions[type]) {
    fdisk_partitions[type] = partition;
  }

  if (NULL != last_partitions[type]) {
    last_partitions[type]->next_by_type = partition;
  }
  last_partitions[type] = partition;

  return(0);
}


void
do_fdisk_disk_free(){

}



void
fdisk_reread(){
  
  int size, parttype;
  char *match, *device, *partition ;


  FILE *f1, *f2;

  int i,j;

  const line_size = 100;
  char *line = (char *) malloc(line_size + 1);
  
  char f2_command[100];

#ifdef USE_SFDISK

#error doesnt work 

  f1 = popen("sfdisk -s", "r");

  while ( fgets(line, line_size, f1)) {
    
    if ( line[0] != '/' ) {
      break;
    }
    
    device = strdup(line);
    match = strstr(device, ":");
    *match = 0;
    
    size = atoi(match + 1);
    
#ifdef DEBUG
    printf("dev: %s, size: %d\n", device, size);
#endif

    do_fdisk_disk_add(device, size);

    sprintf(f2_command, "sfdisk -l %s", device);

    f2 = popen(f2_command, "r");
    
    while ( fgets(line, line_size, f2) ) {

      if (line[0] == '/'){
	
	partition = strdup(line);
	*(strstr(partition, " ")) = 0;
	
	parttype = strtol(line + 49 , NULL, 16);

	if ( parttype != 0) {
#ifdef DEBUG
	  printf("part: %s, type: %x\n", partition, parttype);
#endif
	  do_fdisk_partition_add(partition, parttype);
	}

      }
    }

    pclose(f2);

  }

#else

  f1 = popen("fdisk -l", "r");

  while ( fgets(line, line_size, f1)) {
  
    while (0 != strncmp(line, "Disk", 4)) {
      fgets(line, line_size, f1);
    }

    device = line + 5;
    *(strstr(device,":")) = 0;

    size = 0;
    
#ifdef DEBUG
    printf("dev: %s, size: %d\n", device, size);
#endif

    fdisk_add_disk(device, size);

    while (fgets(line, line_size, f1)) {

      if ( line[0] == '/' ) {
	break;
      }
    }

    while (fgets(line, line_size, f1)) {

      if ( line[0] != '/' ) {
	break;
      }

      partition = strdup(line);
      *(strstr (partition, " ")) = 0;
      
      parttype = strtol(line + 50 , NULL, 16);
      
      if ( parttype != 0) {
#ifdef DEBUG
	printf("part: %s, type: %x\n", partition, parttype);
#endif
	fdisk_add_partition(partition, parttype);
      }

    }
  }
    
#endif
  pclose(f1);

}

