/*  dirfil.c   */
/*  Copyright 1989 Mountain Math Software  */
/*  All Rights Reserved                    */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
// #include <prototypes.h>
#include <stream.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include "dirfil.h"
#include "mkstr.h"
#include "cgidbg.h"
#include "usercom.h"
#ifdef __NT_VC__
#include <io.h>
#endif

inline const char * Ck(const char * x) {return x ? x : "NULL";}

ExamineDirectory::ExamineDirectory(const char * dir, const char * suf,
	const char * base):
	Directory(dir),
	Suffix(suf),
	Base(base),
	DirNames(0),
	BaseLength(0),
	NextDir(0),
	Ndirs(0)
{
	if (Base) BaseLength = strlen(Base);
	if (Directory) if (*Directory) return ;
	Directory = "./" ;
/*
 *	LogOut << "ExamineDirectory(" << Ck(dir) << ", " << Ck(suf) <<
 *		", " << Ck(base) << ")\n" ;
 */
}

ExamineDirectory::~ExamineDirectory()
{
	if (!DirNames) return ;
	for (char ** del = DirNames ; *del ; del++)
		delete  *del;
	delete DirNames ;
}

const char * ExamineDirectory::NextFile()
{
	if (!DirNames) FindFiles(Directory);
	if (!DirNames) return 0 ;
	if (!DirNames[NextDir]) return 0;
	return DirNames[NextDir++] ;
}


void ExamineDirectory::SetDirContents(int Number)
{
	DirNames = new char * [Number+1] ;
	for (int i = 0 ; i <= Number ; i++) DirNames[i] = 0 ;
}

void ExamineDirectory::SetName(int Index, const char * FileName)
{
	// LogOut << "SetName(" << Index << ", " << FileName << ")\n" ;
	DirNames[Index] = Concatenate(FileName);
}

int ExamineDirectory::ValidFile(const char * name)
{
	// LogOut << "Checking File `" << name << "'.\n" ;
	if (Suffix) if (!FindSuffix(name,Suffix)) return 0 ;
	if (Base) if (!FindBase(name,Base)) return 0 ;
	// LogOut << "IsValid\n" ;
	return 1 ;
}

int mystrcmp(const void *a, const void* b)
{
	const char * A = *(const char **) a ;
	const char * B = *(const char **) b ;
	// LogOut << "Comparing: " << A << ", " << B << ")\n" ;
	int Return = strcmp((char *)A,(char *) B);
	// LogOut << "Returning " << Return << "\n" ;
	return Return ;
}


typedef int (*cmp)(const void *, const void *);
void ExamineDirectory::SortDir()
{
	// LogOut << "SortDir Ndirs = " << Ndirs << "\n" ;
	qsort((char *) DirNames,Ndirs,sizeof(DirNames[0]),mystrcmp);
}

int ExamineDirectory::GetNumberFiles()
{
	if (!DirNames) FindFiles(Directory);
	return Ndirs ;
}

int ExamineDirectory::FindFiles(const char * DirName)
{
	DIR * Directory = opendir((char *) DirName) ;
	if (!Directory) {
		// LogOut << "Cannot open\n" ;
		HelpOut << "Cannot open directory `" << DirName << "'.\n" ;
		return 0 ;
	}
	struct dirent * DirRead ;
	while (DirRead = readdir(Directory) )
#ifndef __NT_VC__
		if(DirRead->d_ino)
#endif
		{
			if(ValidFile(DirRead->d_name)) Ndirs++;
			// LogOut<<"File: `"<<DirRead->d_name << "' checked.\n";
		}
	rewinddir(Directory) ;
	if (!Ndirs) {
		// LogOut << "Found no entrys\n" ;
		return 1 ;
	}
	SetDirContents(Ndirs) ;		
	int j=0;
	while (DirRead = readdir(Directory) )
#ifndef __NT_VC__
		if(DirRead->d_ino)
#endif
		if(ValidFile(DirRead->d_name)) 
			SetName(j++,DirRead->d_name);
	closedir (Directory);
	SortDir();
	return 1 ;
	// LogOut << "Exit FindFiles\n" ;
}

const char * ExamineDirectory::IsVersionFile(const char * Name)
{
	if (!Name) return 0 ;
	// LogOut << "IsVersionFile(" << Name << ")\n" ;
	const char * SufPtr = FindLastDot(Name) ;
	if (!SufPtr) return 0 ;
	// LogOut << "SufPtr is " << SufPtr << "\n" ;
	char Last = *SufPtr ;
	if (!Last) return 0 ;
	if (!isascii(Last)) return 0 ;
	if (isdigit(Last)) if (!*(SufPtr+1)) return SufPtr ;
	return 0 ;
}

char * ExamineDirectory::GetVersionFile()
{
	const char * Fil ;
	const char * BaseName = 0 ;
	while (Fil = NextFile()) {

		if (IsVersionFile(Fil)) return Concatenate(Fil) ;
		
		const char * SufPtr = FindLastDot(Fil) ;
		if (!*SufPtr) BaseName = Fil ;
		else if (!*(SufPtr+1)) if (!BaseName) BaseName = Fil ;
	}
	if (BaseName) return Concatenate(BaseName);
	return 0 ;
}

int ExamineDirectory::MoveFile(const char * OldName,const char * NewName)
{
	// LogOut << "MoveFile(" << OldName << ", " << NewName << ")\n" ;
	int Ret = rename(OldName,NewName);
	if (Ret) {
		HelpOut<<
			"There is a problem in updating file versions from:\n" ;
		HelpOut << "`" << OldName << "' to:\n" ;
		HelpOut << "`" << NewName << "'.\n" ;
		SystemErrorMessage();
		return 0 ;
	}
	return !Ret ;
}



int ExamineDirectory::UnLink(const char * ToUnLink)
{
	// LogOut << "UnLink " << ToUnLink << "\n" ;
	char * base = OpdRemoveDirectory(ToUnLink);
	for (int i = 0 ; i < Ndirs ;i++) if (!strcmp(base,DirNames[i])) {
		int Ret = unlink(ToUnLink) ;
		if (Ret) {
			HelpOut <<
	    	"There is a problem in deleting previous file version:\n" ;
			HelpOut << "`" << ToUnLink << ".\n" ;
			SystemErrorMessage();
			delete base ;
			return 0 ;
		}
		for (; i < Ndirs ; i++) DirNames[i] = DirNames[i+1] ;
		Ndirs-- ;
		break ;
		delete base ;
	}
	return 1 ;
}

int ExamineDirectory::ClearName(const char * NameToClear, int NumVers)
{
	// LogOut << "ClearName(" << NameToClear << ", " << NumVers << ")\n" ;
	int Return = 1 ;
	if (!Base || Suffix) return 0 ;
	char * NewName = 0 ;
	char * NewFullName = 0 ;
	char * FullNameToClear = AddSubDirectory(Directory,NameToClear) ;
	for (int i = 0 ; i < Ndirs ; i++)
	    if (!strcmp(NameToClear,DirNames[i])) {
		int LastChar = strlen(NameToClear) - 1 ;
		char Digit = NameToClear[LastChar];
		int Number = Digit - '0' ;
		NewName = Concatenate(NameToClear);
		NewName[LastChar]++;
		NewFullName = AddSubDirectory(Directory,NewName);
		// LogOut << "NewName = " << NewName << "\n" ;
		// LogOut << "NewFullName = " << NewFullName << "\n" ;
		if (Number < NumVers-2) {
			// LogOut << "Clearing " << NewName << "\n" ;
			if (!(Return=ClearName(NewName,NumVers))) break ;
		} else if (!(Return = UnLink(NewFullName))) break ;
		if (!(Return=MoveFile(FullNameToClear,NewFullName))) break ;
		break ;
	}
	delete NewName ;
	delete NewFullName ;
	delete FullNameToClear;
	return Return  ;
}

int ExamineDirectory::NewVersion(const char * TempName,int NumVers)
{
/*
 *	LogOut << "ExamineDirectory::NewVersion(" << TempName << ", " <<
 *		NumVers << ")\n" ;
 *	LogOut << "Directory is " << Directory << "\n" ;
 */
	if (!DirNames) if (!FindFiles(Directory)) return 0 ;
	char * NewName = Concatenate(Base,".0");
	if (DirNames) if (!ClearName(NewName,NumVers)) return 0 ;
	char * FullName = AddSubDirectory(Directory,  NewName );
	int Return = MoveFile(TempName,FullName);
	delete NewName ;
	delete FullName ;
	return Return ;
}


