#include <stdarg.h>
#include "htmlapp.h"
#include "struc/starpasr.h"
#include "struc/iterator.h"
#include "struc/idxcoltn.h"
#include "struc/datablk.h"

id starParser;
#define MAXDATABLOCKNAMELENGTH 80

@implementation CategoryFile

- setCategoryName:(char*)name
{
  _categoryName=name;
  return self;
}

- setFileName:(char*)name
{
  _fileName=(char*)malloc(strlen(name)+1);
  strcpy(_fileName, name);
  return self;
}

- setFile:(FILE*)file
{
  _file=file;
  return self;
}

- (char*)getCategoryName
{
  return _categoryName;
}

- (char*)getFileName
{
  return _fileName;
}

- (FILE*)getFile
{
  return _file;
}

@end

@implementation WDCStarHtmlApplication

- initWith:starObject asChildOf:anObject
{
  return [[self setParentObject:anObject] setStarObject:starObject];
}

- setParentObject:parent
{
  _parent=parent;
  return self;
}

- setStarObject:star
{
  _starObject=star;
  return self;
}

- getParentObject
{
  return _parent;
}

- getStarObject
{
  return _starObject;
}

@end

@implementation WDCStarHtmlMain

#define DEFAULTNUMOFDICS 1

- anyText:(FILE*)file :(const char*)text,...
{
  va_list alist;
  va_start(alist, text);
  vfprintf(file, text, alist);
  va_end(alist);
  return self;
}  

- anchor:(const char*)text : (FILE*) file
{
  fprintf(file, "<A NAME=\"%s\">%s</A>.\n",text,text);
  return self;
}

- link:(const char*)text :(const char*)r1 :(const char*)r2 :(FILE*)file
{
  fprintf(file, "<A HREF=\"%s%s%s\">%s</A>",r1,(strcmp(r2,"")?"#":""),r2,text);
  return self;
}

- newParagraph:(FILE*)file
{
  fprintf(file, "<P>\n");
  return self;
}

- beginUnnumberList:(FILE*)file
{
  fprintf(file, "<UL>\n");
  return self;
}

- endUnnumberList: (FILE*)file
{
  fprintf(file, "</UL>\n");
  return self;
}

- LI: (FILE*)file
{
  fprintf(file, "<LI>");
  return self;
}

- HR: (FILE*)file
{
  fprintf(file, "<HR>\n");
  return self;
}

- beginEM:(FILE*)file
{
  fprintf(file,"<EM>");
  return self;
}

- endEM:(FILE*)file
{
  fprintf(file,"</EM>");
  return self;
}

- beginStrong:(FILE*)file
{
  fprintf(file,"<STRONG>");
  return self;
}

-endStrong:(FILE*)file
{
  fprintf(file,"</STRONG>");
  return self;
}

- beginPreformat:(FILE*)file
{
  fprintf(file,"<PRE>");
  return self;
}

- endPreformat:(FILE*)file
{
  fprintf(file,"</PRE>");
  return self;
}

- emText:(FILE*)file :(const char*)text,...
{
  va_list alist;
  [self beginEM:file];
  va_start(alist, text);
  vfprintf(file, text, alist);
  [self endEM:file];
  va_end(alist);
  return self;
}

- strongText:(FILE*)file :(const char*)text,...
{
  va_list alist;
  [self beginStrong:file];
  va_start(alist, text);
  vfprintf(file, text, alist);
  [self endStrong:file];
  va_end(alist);
  return self;
}

- initWith:(char*)aName,...
{
  char* defaultDics[DEFAULTNUMOFDICS]={"ddl1.1"};
  char** dictionaryNames;
  va_list alist;
  int n, i; 
  char** argvptr;
  char* dirPtr;
  char dicName[80];
  va_start(alist, aName);
  n=va_arg(alist, int);
  argvptr=va_arg(alist, char**);
  va_end(alist);
  printf("Launch %s please wait.\n", argvptr[0]); 
  [self setSTARParser:[WDCStarParser alloc]];
  if (n>1) {
    dirPtr=argvptr[1];
  }
  else 
    dirPtr="../../bin/dic/";
  if (n>2) {
    _numOfDics=n-2;
    dictionaryNames=&argvptr[2];
  }
  else {
    _numOfDics=DEFAULTNUMOFDICS;
    dictionaryNames=&defaultDics[0];
  }
  _outFiles=(FILE**)malloc((_numOfDics*2+1)*sizeof(FILE*));
  _outFileNames=(char**)malloc((_numOfDics*2+1)*sizeof(char*));
  strcpy(dicName, dirPtr); 
  if (dicName[strlen(dicName)-1]!='/') strcat(dicName, "/");
  strcat(dicName, "SFBrowser.html");
  _outFileNames[0]=(char*)malloc(strlen(dicName)+1);
  strcpy(_outFileNames[0], dicName);
  _outFiles[0]=fopen(_outFileNames[0], "w");
  for (i=1; i<=_numOfDics; i++){
    strcpy(dicName, dirPtr); 
    if (dicName[strlen(dicName)-1]!='/') strcat(dicName, "/");
    strcat(dicName, dictionaryNames[i-1]);
    printf("Reading %s please wait.\n", dicName);
    [[self getSTARParser] parseDictionary: dicName];
    strcat(dicName, ".list");
    strcat(dicName, ".html");
    _outFileNames[i]=(char*)malloc(strlen(dicName)+1);
    strcpy(_outFileNames[i], dicName);
    _outFiles[i]=fopen(_outFileNames[i], "w");

    strcpy(dicName, dirPtr); 
    if (dicName[strlen(dicName)-1]!='/') strcat(dicName, "/");
    strcat(dicName, dictionaryNames[i-1]);
    strcat(dicName, ".html");
    _outFileNames[i+_numOfDics]=(char*)malloc(strlen(dicName)+1);
    strcpy(_outFileNames[i+_numOfDics], dicName);
    _outFiles[i+_numOfDics]=fopen(_outFileNames[i+_numOfDics], "w");
  }
  return self;
}

- setSTARParser:aParser
{
  starParser=_starParser=aParser;
  return self;
}

- getSTARParser
{
  return _starParser;
}


- printValue:(int)fileIndex :object :dicIter
{

  // *************************************
  // potential problem from this point.
  // *************************************
  
  id iter, iter1, iter2, currentId;
  id currentValue=[object getValue];
  FILE* file=_outFiles[fileIndex];
  char* valueString;
  char* itemName=(char*)[object getName];
  char blockName[MAXDATABLOCKNAMELENGTH];
  char saveName[MAXDATABLOCKNAMELENGTH];
  char refName[MAXDATABLOCKNAMELENGTH];
  int nameLength,i;
  if (!strcmp(itemName, "loop_")) {
    iter=[[WDCListIterator alloc] initFrom:currentValue];
    [iter goFirst];
    currentId=[[iter getCurrentObject] getContent];
    iter1=[[WDCListIterator alloc] initFrom:currentId];
    [self anyText:file :"\n\n"];
    while ([iter1 goNext]){
      itemName=(char*)[[iter1 getCurrentObject] getName];
      strcpy(blockName, "data");
      strcpy(saveName, "save");
      if (itemName[0]!='\''){
	strcat(blockName, itemName);
	strcat(saveName, itemName);
      }	
      else {
	strncat(blockName, &itemName[1], strlen(itemName)-2);
	strncat(saveName, &itemName[1], strlen(itemName)-2);
      }
      [dicIter reset];
      refName[0]=' ';
      i=0;
      while ([dicIter goNext]){
	i++;
	if ([[[dicIter getCurrentObject] getContent]
	     getDefinitionBlockAtKey :blockName]){
	  strcpy(refName, 
		 (i+_numOfDics==fileIndex)?"":_outFileNames[i+_numOfDics]);
	  break;
	}
      }
      [self anyText:file :"\t"];
/*      if (refName[0]!=' '){
	[self link :itemName :refName :saveName :file];
*/
      if (refName[0]!=' '){
	[self link :itemName :refName :blockName :file];
      }
      else
	[self anyText: file :itemName];
      [self anyText:file :"\n"];
    }
    [iter reset];
    while ([iter goNext]){
      [self anyText:file :"\n"];
      [[iter1 initFrom:[[iter getCurrentObject] getContent]] reset];
      while ([iter1 goNext]){
	currentId=[iter1 getCurrentObject];
	itemName=(char*)[currentId getName];
	currentValue=[currentId getValue];
	 if ((!strcmp(itemName, "_related_item")) 
	   || (!strcmp(itemName, "_list_reference"))
	   || (!strcmp(itemName, "_list_link_parent"))
	   || (!strcmp(itemName, "_list_link_child"))){
	  
/*	if ((!strcmp(itemName, "_category.id"))
	    || (!strcmp(itemName, "_category_key.name"))
	    || (!strcmp(itemName, "_item.category_id"))
	    || (!strcmp(itemName, "_item_linked.parent_name"))
	    || (!strcmp(itemName, "_item_linked.child_name"))){
*/	  valueString=(char*)[currentValue cStringValue];
	  strcpy(blockName, "data");
	  strcpy(saveName, "save");
	  if (valueString[0]!='\''){
	    strcat(blockName, valueString);
	    strcat(saveName, valueString);
	  }
	  else {
	    strncat(blockName, &valueString[1], strlen(valueString)-2);
	    strncat(saveName, &valueString[1], strlen(valueString)-2);
	  }
	  [dicIter reset];
	  refName[0]=' ';
	  i=0;
	  while ([dicIter goNext]){
	    i++;
	    if ([[[dicIter getCurrentObject] getContent]
		 getDefinitionBlockAtKey :blockName]){
	      strcpy(refName, 
		     (i+_numOfDics==fileIndex)?
		     "":
		     _outFileNames[i+_numOfDics]);
	      break;
	    }
	  }
	  [self anyText:file :"\t\t"];
/*	  if (refName[0]!=' '){
	    [self link :valueString :refName :saveName :file];
*/
	  if (refName[0]!=' '){
	    [self link :valueString :refName :blockName :file];
	  }
	  else [self anyText: file :valueString];
	  [self anyText:file :"\n"];
	}
	else if ([currentValue isMemberOfClassNamed:"WDCString"]){
	  [self anyText:file :"\t\t%s\n", [currentValue cStringValue]];
	}
	else if ([currentValue isMemberOfClassNamed:"WDCLineBuffer"]){
	  iter2=[[WDCListIterator alloc] initFrom:currentValue];
	  while ([iter2 goNext]) 
	    [self anyText:file :"\t\t%s\n", 
	     [[iter2 getCurrentObject] cStringValue]];
	  [iter2 free];
	}
      }
    }
    [iter1 free];
    [iter free];
  }
  else if ((!strcmp(itemName, "_related_item")) 
     || (!strcmp(itemName, "_list_reference"))
     || (!strcmp(itemName, "_list_link_parent"))
     || (!strcmp(itemName, "_list_link_child"))){
 
/*  else if ((!strcmp(itemName, "_category.id"))
	   || (!strcmp(itemName, "_category_key.name"))
	   || (!strcmp(itemName, "_item.category_id"))
	   || (!strcmp(itemName, "_item_linked.parent_name"))
	   || (!strcmp(itemName, "_item_linked.child_name"))){
*/    valueString=(char*)[currentValue cStringValue];
    strcpy(blockName, "data");
    strcpy(saveName, "save");
    if (valueString[0]!='\''){
      strcat(blockName, valueString);
      strcat(saveName, valueString);
    }
    else{
      strncat(blockName, &valueString[1], strlen(valueString)-2);
      strncat(saveName, &valueString[1], strlen(valueString)-2);
    }
    [dicIter reset];
    refName[0]=' ';
    i=0;
    while ([dicIter goNext]){
      i++;
      if ([[[dicIter getCurrentObject] getContent]
	   getDefinitionBlockAtKey :blockName]){
	strcpy(refName, 
	       (i+_numOfDics==fileIndex)?"":_outFileNames[i+_numOfDics]);
	break;
      }
    }
    nameLength=strlen(itemName);
    if (nameLength<8) [self anyText:file :"\t"];
    if (nameLength<16) [self anyText:file :"\t"];
    [self anyText:file :"\t"];
/*  
    if (refName[0]!=' '){
      [self link :valueString :refName :saveName :file];
*/    
    if (refName[0]!=' '){
      [self link :valueString :refName :blockName :file];
    }
    else [self anyText: file :itemName];    
  }
  else if ([currentValue isMemberOfClassNamed:"WDCString"]){
    nameLength=strlen(itemName);
    if (nameLength<8) [self anyText:file :"\t"];
    if (nameLength<16) [self anyText:file :"\t"];
    [self anyText:file :"\t%s", [currentValue cStringValue]];
  }
  else if ([currentValue isMemberOfClassNamed:"WDCLineBuffer"]){
    [self anyText:file :"\n"];
    [self anyText:file :"\n"];
    iter=[[WDCListIterator alloc] initFrom:currentValue];
    while ([iter goNext]) [self anyText:file :"%s\n", 
			   [[iter getCurrentObject] cStringValue]];
    [iter free];
  }
  [self anyText:file :"\n\n"];
}

- printInfo:dataBlock :(int)fileIndex
{
  id currentObject, iter, dicIter;
  FILE* file=_outFiles[fileIndex];
  char* itemName;
  char blockName[MAXDATABLOCKNAMELENGTH];
  char saveName[MAXDATABLOCKNAMELENGTH];
  char refName[MAXDATABLOCKNAMELENGTH];
  int i;
  dicIter=[[WDCListIterator alloc] 
	 initFrom:[[self getSTARParser] getDictionaryList]]; 
  [self newParagraph :file];
  [self beginStrong:file];
  [self anchor :[dataBlock getDataBlockName] :file];
  [self endStrong:file];
  [self beginPreformat:file];
  iter=[[WDCListIterator alloc] initFrom :[dataBlock getValue]];
  while ([iter goNext]){
    currentObject=[iter getCurrentObject];
    itemName=(char*)[currentObject getName];
    strcpy(blockName, "data");
    strcpy(saveName, "save");
    if (itemName[0]!='\''){
      strcat(blockName, itemName);
      strcat(saveName, itemName);
    }
    else{
      strncat(blockName, &itemName[1], strlen(itemName)-2);
      strncat(saveName, &itemName[1], strlen(itemName)-2);
    }
    [dicIter reset];
    refName[0]=' ';
    i=0;
    while ([dicIter goNext]){
      i++;
      if ([[[dicIter getCurrentObject] getContent]
	   getDefinitionBlockAtKey :blockName]){
	strcpy(refName, 
	        (i+_numOfDics==fileIndex)?"":_outFileNames[i+_numOfDics]);
	break;
      }
    }
/*    if (refName[0]!=' '){
      [self link :itemName :refName :saveName :file];
*/
    if (refName[0]!=' '){
      [self link :itemName :refName :blockName :file];
    }
    else
      [self anyText: file :itemName];
    [self printValue:fileIndex :currentObject :dicIter];

  }
  [self endPreformat:file];
  [self HR:file];
  [iter free];
  [dicIter free];
}

- printAllDataBlockFor:dictionary :(int)fileIndex
{
  id dataBlocks, iter;
  FILE* file=_outFiles[fileIndex];
  [self anyText:file :"<H2>List of data items in %s</H2>\n",
   [dictionary getName]];
  dataBlocks=[[dictionary getIndexedListOfDataBlocks] sortContents];
  iter=[[WDCListIterator alloc] initFrom:dataBlocks];
  while ([iter goNext]) [self printInfo:[iter getCurrentObject] :fileIndex];
  fflush(file);
  [iter free];
  [dataBlocks free];
  return self;
}

- printAllDataBlockNamesForCategory:(const char*) aName inDictionary:dict 
:(int)fileIndex
{
  id dataBlocks, currentDB, iter, yesString;
  int nameLength, i=0;
  FILE* file=_outFiles[fileIndex];
  char* itemName;
  if (dataBlocks=[[dict getDefinitionBlocksWhos:"_category" 
		   is :(char*)aName]
		  sortContents]){
    iter=[[WDCListIterator alloc] initFrom:dataBlocks];
    [self beginPreformat:file];
    [self anyText:file :"\t\t\t\t\tlist\tmanda\trefer\n\n"];
    while ([iter goNext]){
      i++;
      currentDB=[iter getCurrentObject];
      itemName=(char*)[currentDB getName];
      [self link:itemName 
       :_outFileNames[fileIndex+_numOfDics] :itemName :file];
      nameLength=strlen(itemName);
      if (nameLength<8) [self anyText:file :"\t"];
      if (nameLength<16) [self anyText:file :"\t"];
      if (nameLength<24) [self anyText:file :"\t"];
      if (nameLength<32) [self anyText:file :"\t"];
      [self anyText:file :"\t%s", [[[currentDB getDataItem:"_list"] 
				    getValue] cStringValue]];
      [self anyText:file :"\t%s", [[[currentDB getDataItem:"_list_mandatory"] 
				    getValue] cStringValue]];    
      [self anyText:file :"\t%s\n", [[[currentDB getDataItem
				       :"_list_reference"] 
				      getValue] cStringValue]];
      
    }
    [self endPreformat:file];
    [self newParagraph:file];
    [dataBlocks free];
  }
  fflush(file);
  [iter free];
  return self;
}

- printAllCategoryWithDataItemNamesFor:dictionaries
{
  id currentDic, names, dicIter, iter;
  int i=0;
  FILE* file;
  dicIter=[[WDCListIterator alloc] initFrom:dictionaries];
  iter=[WDCListIterator alloc];
  while ([dicIter goNext]){
    i++;
    file=_outFiles[i];
    currentDic=[[dicIter getCurrentObject] getContent];
    if (names=[[currentDic getAllUnique :"_category"] sortContents]){
      [[self HR:file] newParagraph:file];
      [self strongText:file :"List of data items by category in %s\n",
       [currentDic getName]];
      [self newParagraph:file];
      [self beginUnnumberList:file];
      printf("Generating summary of category in file: %s\n",_outFileNames[i]);
      [[iter initFrom:names] reset];
      while ([iter goNext]){
	[self LI:file];
	[self anchor:[[iter getCurrentObject] cStringValue] :file];
	[self anyText:file :"\n"];
	[self printAllDataBlockNamesForCategory:[[iter getCurrentObject] 
						 cStringValue]
	 inDictionary :currentDic :i];
      }
      [self endUnnumberList:file];
      [self newParagraph:file];
      fflush(file);
      [names free];
    }
  }
  [iter free];
  [dicIter free];
  return self;
}  

- printAllCategoryNamesFor:dictionaries
{
  id currentDic, names, dicIter, iter;
  int i=0;
  FILE* file;
  dicIter=[[WDCListIterator alloc] initFrom:dictionaries];
  iter=[WDCListIterator alloc];
  while ([dicIter goNext]){
    i++;
    file=_outFiles[i];
    currentDic=[[dicIter getCurrentObject] getContent];
    if (names=[[currentDic getAllUnique :"_category"] sortContents]){
      printf("Generating list of categories in file: %s\n", _outFileNames[i]);
      [self anyText:file 
       :"<TITLE>Star File Browser: %s</TITLE>\n",
       _outFileNames[i]];
      [self anyText:file :"<H1>Summary information in: %s</H1>\n",
       _outFileNames[i]];
      [self newParagraph:file];
      [self beginStrong:file];
      [self anyText:file :"List of categories in "];
      [self anchor:[currentDic getName] :file];
      [self endStrong:file];
      [self newParagraph:file]; 
      [self beginUnnumberList:file];
      [[iter initFrom:names] reset];
      while ([iter goNext]){
	[self LI:file];
	[self link:[[iter getCurrentObject] cStringValue] 
	 :"" :[[iter getCurrentObject] cStringValue] :file];
	[self anyText:file :"\n"];
      }
      [self endUnnumberList:file];
      [self newParagraph:file];
      fflush(file);
      [names free];
    } else {
      free(_outFileNames[i+_numOfDics]);
      fclose(_outFiles[i+_numOfDics]);
      _outFileNames[i+_numOfDics]=_outFileNames[i];
      _outFiles[i+_numOfDics]=_outFiles[i];
    }
  }
  [iter free];
  [dicIter free];
  return self;
}  

- run
{
  id dictionaries, iter;
  int i=0;
  printf("Generating HTML files.\n"); 
  dictionaries=[[self getSTARParser] getDictionaryList];
  [self anyText:_outFiles[0] :"<TITLE>Star File Browser</TITLE>\n"];
  [self anyText:_outFiles[0] :"<H1>List of files:</H1>\n"];
  [self beginUnnumberList:_outFiles[0]];
  iter=[[WDCListIterator alloc] initFrom:dictionaries];
  while ([iter goNext]){
    i++;
    [self LI:_outFiles[0]];
    [self link:[[[iter getCurrentObject] getContent] getName]
     :_outFileNames[i] :[[[iter getCurrentObject] getContent] getName]
     :_outFiles[0]];
    [self anyText:_outFiles[0] :"\n"];
  }
  fflush(_outFiles[0]);
  [self endUnnumberList:_outFiles[0]];
  [self printAllCategoryNamesFor:dictionaries];
  [self printAllCategoryWithDataItemNamesFor:dictionaries];
  [iter reset];
  i=_numOfDics;
  while ([iter goNext]){
    printf("Generating data block content file: %s\n",_outFileNames[++i]);
    [self anyText:_outFiles[i] :"<HEAD>\n"];
    [self anyText:_outFiles[i] :"<TITLE>Star File Browser: %s</TITLE>",
     _outFileNames[i]];
    [self anyText:_outFiles[i] :"</HEAD>\n"];
    [self newParagraph:_outFiles[i]];
    [self printAllDataBlockFor:[[iter getCurrentObject] getContent] :i];
    fflush(_outFiles[i]);
  }
  [iter free];
  [dictionaries free];
  [self HR:_outFiles[0]];
  [self newParagraph:_outFiles[0]];
  [self anyText:_outFiles[0] :"These html's have been generated by a CIFter \
--- tools to facilitate the use of Crystallographic Information Files\n"];
  [self anyText:_outFiles[0] :" (CIF's). CIFters are funded by the National Science Foundation grant number "];
  [self link:"BIR 93-10154." :"gopher://stis.nsf.gov:70/0R0-2141-/.index/ftp/awards93/awd9310/a9310154" :"" :_outFiles[0]];
  [self newParagraph:_outFiles[0]];
  [self anyText:_outFiles[0] :"Copyright (C) 1994 The Trustees of Columbia University in the City of New York."];
  for (i=0; i<(_numOfDics*2)+1; i++) fclose(_outFiles[i]);
  return self;
}

@end





