#include <stdio.h>
#include "string.h"
#include "common.h"
#include "map.h"
#include "segment.h"
#include "public.h"
#include "list.h"
#include "hash.h"
#include "allocate.h"

extern uint classlens[SUPPORTED_CLASSES] ;
extern LIST *classlists[SUPPORTED_CLASSES];
extern HASHREC **PublicHash;

/*
 * Dump class names out
 */
static void DumpClasses(FILE *out)
{
  int i;
  fputc('\n',out);
  fprintf(out," Start    Length  \t\t\tClass\n");
  for (i=0; i<IGNORED_CLASSES; i++)
    if (classlens[i]) {
			LIST *p=classlists[i];
			SEGMENT *d = p->data;
			fprintf(out," %08x %08x\t\t\t%s\n", d->absoffset, classlens[i], d->classname);
		}
}
/* 
 * Dump detailed segment map
 */
static void DumpSegments(FILE *out)
{
  int i;
  fprintf(out,"\n\nDetailed map of segments\n\n");
  for (i=0; i<IGNORED_CLASSES; i++)
    if (classlens[i]) {
			LIST *p=classlists[i];
			while (p) {
				SEGMENT *d = p->data;
				char *pos;
				pos = strrchr(d->module,'\\');
				if (!pos)
					pos = d->module;
				else
					pos++;
			  fprintf(out," %08x %08x C=%-8s S=%-8s M=%-11s ACBP=%X\n"	,
					d->absoffset, d->length, d->classname, d->segname, pos, d->acbp);
    		p = p->link;
 			}
		}
}
/*
 * Count the number of publics
 */
static uint CountPublics()
{
  int i,rv = 0;
  for (i=0; i< HASH_TABLE_SIZE; i++) {
    PUBLIC *p = PublicHash[i];
		while(p) {
			rv++;
			p = p->link;
		}
	}
  return(rv);
}
/*
 * Move the publics to a list
 */
static void PublicsToList(PUBLIC **list)
{
  int i, pos=0;
  for (i=0; i < HASH_TABLE_SIZE; i++) {
    PUBLIC *p = PublicHash[i];
		while (p) {
			list[pos++] = p;
			p = p->link;
		}
	}
}
/*
 * Output the public list
 */
static void OutputPublics(FILE *out, PUBLIC **list, uint len)
{
  int i;
  static char *idle = "idle", *notidle = "";
  for (i=0; i < len; i++) {
		PUBLIC *p = list[i];
	  char *cs=notidle;
    if (!p->referenced)
			cs = idle;
    fprintf(out," %08x  %-6s %s\n",p->absoffset, cs, p->name);
  }
}
/*
 * Sort the public list by name
 */
static void SortByName( PUBLIC **list, uint len)
{
  int i,j;
  for (i=0; i <len; i++)
    for (j=i+1; j< len; j++)
			if (strcmp(list[i]->name,list[j]->name) > 0) {
        PUBLIC *temp = list[i];
				list[i] = list[j];
				list[j] = temp;
			}
}
/*
 * Sort the public list by value
 */
static void SortByValue( PUBLIC **list, uint len)
{
  int i,j;
  for (i=0; i <len; i++)
    for (j=i+1; j< len; j++)
			if (list[i]->absoffset < list[j]->absoffset) {
        PUBLIC *temp = list[i];
				list[i] = list[j];
				list[j] = temp;
			}
}
/*
 * Main routine to sort and dump publics
 */
static void DumpPublics(FILE *out)
{
  PUBLIC **list;
  uint len = CountPublics();
  list = (PUBLIC **)AllocateMemory(len*sizeof(PUBLIC *));
  PublicsToList(list);
  
  fprintf(out,"\n  Address     Publics by Name\n\n");
	SortByName(list,len);
	OutputPublics(out, list,len);
  fprintf(out,"\n  Address     Publics by Value\n\n");
	SortByValue(list,len);
	OutputPublics(out, list,len);
  DeallocateMemory(list);
}
/*
 * Routine to write the map file
 */
void WriteMapFile(char *name, uint mode)
{
  FILE *out;
  if (mode == MAP_NONE) return;

  if ((out =fopen(name,"w")) == 0)
    fatal("Can't create map file %s", name);

  DumpClasses(out);
  if (mode == MAP_NORMAL) {
    fclose(out);
		return;
  }
  if (mode == MAP_EXTENDED) {
		DumpSegments(out);
  }

  DumpPublics(out);

}