#include <stdio.h>
#include <stdlib.h>
#include <dos/dos.h>
#include <dos/datetime.h>
#include <clib/dos_protos.h>
#include <string.h>

#define MAXLEN 255

typedef struct lcell
{
  char *item;
  struct lcell *next;
}LCELL, *LCPTR, *LIST;

LIST cons(LIST,char *);
void input_recent(LIST);
void cleanup();
void merge(LIST,char *);
void openfiles();
void getdate(char *,struct DateTime *);

FILE *recent=NULL, *index=NULL, *output=NULL;
LIST recent_list=NULL;
int identical=0, weeks_diff=0;
LONG *args[]={NULL,NULL,NULL,FALSE};
struct ReadArgs *rdargs=NULL;
char *version_info="\0$VER: MergeRecent 37.2 (30.6.95)";

main()
{
  char line[MAXLEN+1];
  int len=0;
  struct DateTime recent_date, index_date, output_date;
  
  atexit(cleanup);
  rdargs=ReadArgs("INDEX/A,RECENT/A,OUTPUT,FORCE/K",args,NULL);
  if (rdargs==NULL)
  {
    PrintFault(IoErr(),NULL);
    exit(RETURN_WARN);
  }
  openfiles();
  fgets(line,MAXLEN,recent);
  getdate(line,&recent_date);
  while (!feof(recent) && line[0]=='|')
    fgets(line,MAXLEN,recent);
  if (feof(recent))
  {
    fprintf(stderr,"Premature end of file in %s.\n",args[1]);
    exit(RETURN_ERROR);
  }
  recent_list=cons(cons(NULL,strdup(line)),NULL);
  fgets(line,MAXLEN,index);
  getdate(line,&index_date);
  if ( ((index_date.dat_Stamp.ds_Days -
	 index_date.dat_Stamp.ds_Days) > 7) && !args[4] )
    {
      fprintf(stderr,"Index file is more than a week older than recent file.\n");
      exit(RETURN_ERROR);
    }
  fputs(strcat("| Local Aminet index on ",recent_date.dat_StrDate),output);
  fputc('\n',output);
  fgets(line,MAXLEN,index);
  if (strncmp(line,"| Ages correct upto ",20)==0)
  {
    getdate(line,&output_date);
    weeks_diff=(recent_date.dat_Stamp.ds_Days-
		output_date.dat_Stamp.ds_Days)/7;
    output_date.dat_Stamp.ds_Days=output_date.dat_Stamp.ds_Days+(weeks_diff*7);
    output_date.dat_StrDay  = NULL;
    output_date.dat_StrDate = line+20;
    if (!DateToStr(&output_date))
    {
      fprintf(stderr,"Couldn't calculate date of new index.\n");
      exit(RETURN_ERROR);
    }
  }
  else
  {
    fputs(strcat("| Ages correct upto ",index_date.dat_StrDate),output);
    fputc('\n',output);
  }
  while (!feof(index) && line[0]=='|')
  {
    fputs(line,output);
    fgets(line,MAXLEN,index);
  }
  if (output!=stdout)
    printf("Sorting recent file list\n");
  input_recent(recent_list);
  if (output!=stdout)
    printf("Merging lists...\n");
  merge(recent_list,line);
  if (output!=stdout)
    printf("%d identical filename%c skipped.\n",identical,(identical==1)?'\0':'s');
  exit(RETURN_OK);
}

void input_recent(LIST recent_list)
{
  char line[MAXLEN+1];
  
  fgets(line,MAXLEN,recent);
  while (!feof(recent)) /* does this stop before or after eof? */
  {
    LCPTR curr=recent_list->next, prev=recent_list;
    BOOL found=FALSE;
    
    if (line[0]!='\n')
    {
      while (curr!=NULL && !found)
      {
	int dir_cmp=strncmp(curr->item+19,line+19,10);
	int file_cmp=strnicmp(curr->item,line,18);
	if ( (dir_cmp==0 && file_cmp>0) || (dir_cmp>0) )
	  found=TRUE;
	else
	{
	  prev=curr;
	  curr=curr->next;
	}
      }
      prev->next=cons(curr,strdup(line));
    }
    fgets(line,MAXLEN,recent);
  }
}

void getdate(char *line, struct DateTime *dt)
{
  char *new=strdup(line);
  int i=strlen(new)-1;
  
  new[i]='\0';
  while (i>0 && new[i]!=' ')
    i=i-1;
  dt->dat_Format  = FORMAT_DOS;
  dt->dat_Flags   = 0;
  dt->dat_StrDate = strdup(new+i+1);
  dt->dat_StrTime = NULL;
  if (!StrToDate(dt))
  {
    fprintf(stderr,"Unable to read valid date.\n");
    exit(RETURN_ERROR);
  }
}

LIST cons(LIST tail, char *line)
{
  LIST newlist=(LCELL *)calloc(1,sizeof(LCELL));
  if (newlist==NULL)
  {
    PrintFault(ERROR_NO_FREE_STORE,NULL);
    exit(10);
  }
  newlist->item=line;
  newlist->next=tail;
  return(newlist);
}

void openfiles()
{
  index=fopen(args[0],"r");
  if (index==NULL)
  {
    PrintFault(IoErr(),args[0]);
    exit(RETURN_ERROR);
  }
  recent=fopen(args[1],"r");
  if (recent==NULL)
  {
    PrintFault(IoErr(),args[1]);
    exit(RETURN_ERROR);
  }
  if (args[2]!=NULL)
  {
    output=fopen(args[2],"w");
    if (output==NULL)
    {
      PrintFault(IoErr(),args[2]);
      exit(RETURN_ERROR);
    }
  }
  else
    output=stdout;
}

void cleanup()
{
  if (rdargs!=NULL)
    FreeArgs(rdargs);
  if (index!=NULL)
    fclose(index);
  if (recent!=NULL)
    fclose(recent);
  if (output!=stdout)
    fclose(output);
}

void merge(LIST recent_list,char *first_line)
{
  char line[MAXLEN+1], insert_line[MAXLEN+1];
  LCPTR curr=recent_list->next;
  
  strcpy(line,first_line);
  while (!feof(index))
  {
    if (curr!=NULL)
    {
      int dir_cmp=strncmp(line+19,curr->item+19,10);
      int file_cmp=strnicmp(line,curr->item,18);
      if ( (dir_cmp>0) || ((dir_cmp==0) && (file_cmp>=0)) )
      {
	if (file_cmp!=0)
	{
	  strncpy(insert_line,curr->item,34);
	  strcpy(insert_line+34,"   0");
	  strcpy(insert_line+38,curr->item+34);
	  fputs(insert_line,output);
	}
	else
	  identical=identical+1;
	curr=curr->next;
      }
      else
      {
	if (weeks_diff==0)
	  fputs(line,output);
	else
	{
	  int age=atoi(line+34)+weeks_diff;
	  char newage[5];
	  sprintf(newage,"%4d",age);
	  strncpy(line+34,newage,4);
	  fputs(line,output);
	}
	fgets(line,MAXLEN,index);
      }
    }
    else
    {
      if (weeks_diff==0)
	fputs(line,output);
      else
      {
	int age=atoi(line+34)+weeks_diff;
	char newage[5];
	sprintf(newage,"%4d",age);
	strncpy(line+34,newage,4);
	fputs(line,output);
      }
      fgets(line,MAXLEN,index);
    }
  }
  while (curr!=NULL)
  {
    strncpy(insert_line,curr->item,34);
    strcpy(insert_line+34,"   0");
    strcpy(insert_line+38,curr->item+34);
    fputs(insert_line,output);
    curr=curr->next;
  }
}

