/*
 * NcdT -- directory tree printer with extended capabilities
 * (C) 1999-2001 by Pawel Wiecek <coven@vmh.net>
 * See Copying file for licence.
 * 
 * Main code
 */

#include <stdio.h>
#include <sys/stat.h>
#include <string.h>
#include <dirent.h>
#include <stdlib.h>
#include <getopt.h>
#include "ncdt.h"

struct TREE *root;
int dirsonly=0;
int dirbrate=0;

static struct option longopts[]={
 {"help",0,NULL,'?'},
 {"dirs",0,NULL,'d'},
 {"bitrate",0,NULL,'b'},
 {"prefix",1,NULL,1},
 {NULL,0,NULL,0}
};

int main(int argc, char *argv[]) {
 char *rootname, *title;
 unsigned long tt;
 int opt, b1, b2;

 while(1) {
  if((opt=getopt_long(argc,argv,"db?",longopts,NULL))<0)
   break;
  switch(opt) {
   case '?':
    help();
    break;
   case 'd':
    dirsonly=1;
    break;
   case 'b':
    dirbrate=1;
    break;
   case 1:
    printf(":%s\n",optarg);
    break;
  }
 }
 if(argc-optind>0) rootname=argv[optind];
              else rootname=".";
 if(argc-optind>1) title=argv[optind+1];
              else title=rootname;
 root=malloc(sizeof(struct TREE));
 root->name=strdup(title);
 root->len=root->dirdown=root->brmin=root->brmax=0;
 root->isdir=1;
 t_scan(root,rootname);
 t_fix(root,&tt,&b1,&b2);
 t_print(root,"");
 t_free(root);
 return 0;
}

void t_scan(struct TREE *t, char *r) {
 DIR *dir;
 struct dirent *ent;
 struct stat st;
 char buf[4096];
 int m=0;
 struct TREE *p=NULL;

 dir=opendir(r);
 if(!dir) return;
 while((ent=readdir(dir))) {
  if(!strcmp(ent->d_name,".")||!strcmp(ent->d_name,"..")) continue;
  if(m) p=p->brother=malloc(sizeof(struct TREE));
   else p=t->son=malloc(sizeof(struct TREE));
  m=1;
  p->name=strdup(ent->d_name);
  sprintf(buf,"%s/%s",r,ent->d_name);
  p->son=NULL;
  lstat(buf,&st);
  p->len=st.st_size;
  p->time=p->dirdown=p->brmin=p->brmax=0;
  if(st.st_mode&S_IFDIR) {
   p->isdir=1;
   t_scan(p,buf);
  } else {
   p->isdir=0;
   if((st.st_mode&S_IFREG)&&(endswith(ent->d_name,".mp3")
			   ||endswith(ent->d_name,".MP3")))
    mp3info(buf,p);
  }
 }
 if(p) p->brother=NULL;
 closedir(dir);
}

int t_fix(struct TREE *t, unsigned long *tim, int *bmin, int *bmax) {
 unsigned long len;
 
 if(t->son)
  t->len=t_fix(t->son,&t->time,&t->brmin,&t->brmax);
 if(t->brother) {
  len=t->len+t_fix(t->brother,tim,bmin,bmax);
  t->dirdown=(t->brother->isdir || t->brother->dirdown);
  *tim+=t->time;
  if(t->brmin&&((t->brmin<*bmin)||!*bmin)) *bmin=t->brmin;
  if(t->brmax>*bmax) *bmax=t->brmax;
  return len;
 } else {
  *tim+=t->time;
  if(t->brmin&&((t->brmin<*bmin)||!*bmin)) *bmin=t->brmin;
  if(t->brmax>*bmax) *bmax=t->brmax;
  return t->len;
 }
}

void t_print(struct TREE *t, char *pref) {
 char npref[256];
 int brd;
 
 if(t->son && t->time) {
  if(dirbrate) {
   if(t->brmin==t->brmax)
    sprintf(npref,"  <%s %d>",nicetime(t->time),t->brmin);
   else
    sprintf(npref,"  <%s %d-%d>",nicetime(t->time),t->brmin,t->brmax);
  } else {
   sprintf(npref,"  <%s>",nicetime(t->time));
  }
  t->name=realloc(t->name,strlen(t->name)+strlen(npref)+1);
  strcat(t->name,npref);
 }
 if(dirsonly) brd=t->dirdown;
         else brd=!!t->brother;
 if(!dirsonly || t->isdir)
  printf("%s%c-- [%11s] %s\n",pref,brd?'|':'`',nicenum(t->len),t->name);
 if(t->son) {
  sprintf(npref,"%s%c  ",pref,brd?'|':' ');
  t_print(t->son,npref);
 }
 if(t->brother) t_print(t->brother,pref);
}

void t_free(struct TREE *t) {
 if(t->son) t_free(t->son);
 if(t->brother) t_free(t->brother);
 free(t->name);
 free(t);
}
