#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "rr.h"
#include "rrparser.h"
#include "errors.h"
#include "zone.h"

/*
 * zone file format:
 * <#RR><RR0len><RR0><RR1len><RR1>...<RRnlen><RRn>
 * 
 * where #RR = n (=>counted w/o RR0) [uint_16]
 * 
 * where RR0 is special type T_ZONE with RDATA format:
 * <ORIGIN/ZONENAME(labelsstr)>
 * (ttl not meanable); RDATA len not checked to be
 * compatible, only first field read'd
 */

int
read_zone(int fd, zone_t *zone) {
  rr_t zonerr;
  int cnt, ret;
  
  read(fd, &zone->rrs, 2);
  
  if ((ret = read_raw_rr(fd, &zonerr)))
    return ret;
  
  if (ntohs(zonerr.rrtype) != T_ZONE)
    return XEINVAL;

  zone->origin = malloc(zonerr.rdata[0] + 1);
  strncpy(zone->origin, zonerr.rdata, zonerr.rdata[0] + 1);

  zone->soa = NULL;

  zone->rr = malloc(ntohs(zone->rrs) * sizeof(rr_t));
  
  for (cnt=0; cnt < ntohs(zone->rrs); cnt++) {
    
    if ((ret = read_raw_rr(fd, &zone->rr[cnt])))
      return ret;
    
    if (ntohs(zone->rr[cnt].rrtype) == T_SOA)
      zone->soa = &zone->rr[cnt];
    
  }

  if (! zone->soa)
    return XENOENT;
  
  return XENONE;
}

int
dump_zone(int fd, zone_t *zone) {
  rr_t zonerr;
  int cnt, ret;
  
  write(fd, &zone->rrs, 2);
  
  zonerr.name = "";
  zonerr.rrtype = htons(T_ZONE);
  zonerr.rrclass = htons(1);
  zonerr.ttl = 0;
  zonerr.rdlength = zone->origin[0] + 1;
  zonerr.rdata = malloc(zonerr.rdlength);
  
  strncpy(zonerr.rdata, zone->origin, zonerr.rdlength);
  zonerr.rdlength = htons(zonerr.rdlength);
    
  if ((ret = dump_raw_rr(fd, &zonerr)))
    return ret;

  for (cnt=0; cnt < ntohs(zone->rrs); cnt++) {
    
    if ((ret = dump_raw_rr(fd, &zone->rr[cnt])))
      return ret;
    
  }
  
  return XENONE;
}

int
dump_str_zone(char **str_zone, zone_t *zone) {
  int cnt, ret, len;
  static char **str_rr;
  char **rr_list;
  int rr_num;
  
  str_rr = malloc(sizeof(char *)); /* XXX: stack corruptions around otherwise maybe */
  
  labels2domain(zone->origin);

  len = strlen(zone->origin);
  
  rr_num = htons(zone->rrs);
  rr_list = malloc(rr_num * sizeof(char *));
  
  for (cnt=0; cnt < rr_num; cnt++) {
    
    if ((ret = dump_str_rr(str_rr, &zone->rr[cnt])))
      return ret;
    
    len += strlen(*str_rr) + 1;
    rr_list[cnt] = *str_rr;
    
  }
  
  *str_zone = malloc(len + rr_num + 2);
  sprintf(*str_zone, "%s\n", zone->origin);

  for (cnt=0; cnt < rr_num; cnt++) {
    
    strcat(*str_zone, rr_list[cnt]);
    strcat(*str_zone, "\n");
    
    //free(rr_list[cnt]); /* XXX: leak? */
    
  }

  return XENONE;
}

int
read_str_zone(FILE *f, zone_t *zone) {
  char str_rr[256];
  int cnt;
  
  zone->origin = malloc(257);
  fgets(zone->origin+1, 255, f);
  zone->origin[0] = strlen(zone->origin + 2);
  
  domain2labels(zone->origin);
  
  zone->rr = NULL;
  zone->soa = NULL;
  
  for(cnt=0; fgets(str_rr, 255, f); cnt++) {
    
    zone->rr = realloc(zone->rr, (cnt+1) * sizeof(rr_t)); /* XXX: realloc() */
    
    read_str_rr(str_rr, &zone->rr[cnt]);
    
    if (ntohs(zone->rr[cnt].rrtype) == T_SOA)
      zone->soa = &zone->rr[cnt];
    
  }
  
  if (! zone->soa)
    return XENOENT;
  
  zone->rrs = htons(cnt);

  return XENONE;
}
