#include <common/pathfnd.hpp>
#include <common/stdio.hpp>
#include <common/profile.hpp>
#include <common/diskinfo.hpp>

PathFind::PathFind(void)
: mIsOkay(FALSE)
{
  mUpDirString="..";
  mCurrDirString=".";
  mBackSlashString="\\";
  mStarDotStarString="*.*";
  mPathString="PATH";
	mSemicolonString=";";
  mWinDirString="windir";
  getPathBlock();
}

PathFind::~PathFind()
{
}

WORD PathFind::isFile(const String &pathFileName)
{
	return mFindData.findFirst(pathFileName);
}

BOOL PathFind::hasWildCard(String &pathFileSpec)const
{
  if(-1==pathFileSpec.strpos("*")&&-1==pathFileSpec.strpos("?"))return FALSE;
	return TRUE;
}

BOOL PathFind::hasPath(String &pathFileSpec)const
{
  if(-1==pathFileSpec.strpos(":"))return FALSE;
	return TRUE;
}

WORD PathFind::dirList(String pathEntry,Block<String> &subDirList)
{
	subDirList.remove();
	if(pathEntry.isNull())getWinDir(pathEntry);
	if(pathEntry.strstr("*"))getDirEntries(pathEntry,subDirList);
  else getPathTranscend(pathEntry,subDirList);
  return subDirList.size();
}

WORD PathFind::fileList(String pathFileSpec,Block<String> &entryList)
{
  int strLength(pathFileSpec.length());
  entryList.remove();
	if(pathFileSpec.isNull())return FALSE;
	if(!hasPath(pathFileSpec))insertPath(pathFileSpec);
	if(!hasWildCard(pathFileSpec))
	{
    if(pathFileSpec.operator[](strLength-1)=='\\'||pathFileSpec.operator[](strLength-1)=='/')pathFileSpec+=mStarDotStarString;
		else pathFileSpec+=mBackSlashString+mStarDotStarString;
	}
	if(!mFindData.findFirst(pathFileSpec,FindData::FileArchive))return FALSE;
  if(mFindData.attributes()&FindData::FileArchive)entryList.insert(&mFindData.fileName());
	while(mFindData.findNext())if(mFindData.attributes()&FindData::FileArchive)entryList.insert(&mFindData.fileName());
	return (entryList.size()?TRUE:FALSE);
}

WORD PathFind::findFile(const String &pureFileName,String &pathFileName)
{
  String searchDir;

  if(!mIsOkay)return FALSE;
	if(pureFileName.isNull())return FALSE;
  if(isFile(pureFileName))
	{
	  pathFileName=pureFileName;
		return TRUE;																		
	}
  size_t numEntries((size_t)mPathEntry.size());
  for(int itemIndex=0;itemIndex<numEntries;itemIndex++)
  {if(searchPath(mPathEntry[itemIndex],pureFileName,pathFileName))return TRUE;}
  if(getWinDir(searchDir)&&searchPath(searchDir,pureFileName,pathFileName))return TRUE;
  if(getWindowsDirectory(searchDir)&&searchPath(searchDir,pureFileName,pathFileName))return TRUE;
  if(getSystemDirectory(searchDir)&&searchPath(searchDir,pureFileName,pathFileName))return TRUE;
  if(getCurrDir(searchDir)&&searchPath(searchDir,pureFileName,pathFileName))return TRUE;
  return FALSE;
}

WORD PathFind::searchPath(String pathEntry,String pureFileName,String &pathFileName)
{
  if(pathEntry.isNull())return FALSE;
  Block<String> subDirList;
  String searchFileName;
  String transcendPath;

  if(pathEntry.isNull())return FALSE;
  fixupPathName(pathEntry);
  searchFileName=pathEntry;
  searchFileName+=pureFileName;
  if(isFile(searchFileName)){pathFileName=searchFileName;return TRUE;}
  return FALSE;
}

WORD PathFind::searchPathTranscend(String pathEntry,String pureFileName,String &pathFileName)
{
  if(pathEntry.isNull())return FALSE;
  Block<String> subDirList;
  String searchFileName;
  String transcendPath;

  if(pathEntry.isNull())return FALSE;
  if(!canTranscend(pathEntry))
  {
		searchFileName=pathEntry;
		searchFileName+=mBackSlashString;
		searchFileName+=pureFileName;
		if(isFile(searchFileName)){pathFileName=searchFileName;return TRUE;}
	  return FALSE;
  }
	searchFileName=pathEntry;
	searchFileName+=mBackSlashString;
	searchFileName+=pureFileName;
	if(isFile(searchFileName)){pathFileName=searchFileName;return TRUE;}
	subList(subDirList,pathEntry);
	WORD itemCount((size_t)subDirList.size());
	for(int itemIndex=0;itemIndex<itemCount;itemIndex++)
	{
		transcendPath=pathEntry;
		transcendPath+=mBackSlashString;
		transcendPath+=subDirList[itemIndex];
	  if(searchPathTranscend(transcendPath,pureFileName,pathFileName))return TRUE;
  }
  return FALSE;
}

WORD PathFind::getPathTranscend(String pathEntry,Block<String> &pathFileName)
{
	if(pathEntry.isNull())return FALSE;
	Block<String> subDirList;
	String searchFileName;
	String transcendPath;
	String pathEntryExtension;

	if(pathEntry.isNull())return FALSE;
	if(!canTranscend(pathEntry))
	{
		searchFileName=pathEntry;
		searchFileName+=mBackSlashString;
		searchFileName+=mStarDotStarString;
		return getDirectoryFileEntries(searchFileName,pathFileName);
	}
	searchFileName=pathEntry;
	searchFileName+=mBackSlashString;
	searchFileName+=mStarDotStarString;
	getDirectoryFileEntries(searchFileName,pathFileName);
	subList(subDirList,pathEntry);
	WORD itemCount((size_t)subDirList.size());
	for(int itemIndex=0;itemIndex<itemCount;itemIndex++)
	{
		transcendPath=pathEntry;
		transcendPath+=mBackSlashString;
		transcendPath+=subDirList[itemIndex];
    getPathTranscend(transcendPath,pathFileName);
  }
  return pathFileName.size();
}

WORD PathFind::getDirectoryFileEntries(String pathEntryFileSpec,Block<String> &entryStrings)
{
	Profile iniProfile;
	WORD specEntries(0);
	String pathEntrySpec;
	String pathFileName;

	if(pathEntryFileSpec.isNull())return specEntries;
	pathEntrySpec=pathEntryFileSpec;
	iniProfile.makeDirectoryName(pathEntrySpec);
	pathEntrySpec+=mBackSlashString;
	if(mFindData.findFirst(pathEntryFileSpec))
	{
		pathFileName=pathEntrySpec;
		pathFileName+=mFindData.fileName();
		pathFileName.lower();
		entryStrings.insert(&pathFileName);
		specEntries++;
		while(mFindData.findNext())
		{
			pathFileName=pathEntrySpec;
			pathFileName+=mFindData.fileName();
			pathFileName.lower();
			entryStrings.insert(&pathFileName);
			specEntries++;
		}
	}
	return specEntries;
}

WORD PathFind::getDirEntries(String pathEntryFileSpec,Block<String> &entryStrings)
{
  Profile iniProfile;
	WORD specEntries(0);
	String pathFileName;
	String dirName;
  FindData findData;

	if(pathEntryFileSpec.isNull())return specEntries;
	dirName=pathEntryFileSpec;
	if(!iniProfile.makeDirectoryName(dirName))dirName=String();
	if(!findData.findFirst(pathEntryFileSpec))
	{
		pathFileName=dirName;
    if(!pathFileName.isNull())pathFileName+="/";
		pathFileName+=findData.fileName();
		pathFileName.lower();
		entryStrings.insert(&pathFileName);
		specEntries++;
		while(!findData.findNext())
		{
			pathFileName=dirName;
			if(!pathFileName.isNull())pathFileName+="/";
			pathFileName+=findData.fileName();
			pathFileName.lower();
			entryStrings.insert(&pathFileName);
			specEntries++;
		}
	}
	return specEntries;
}

void PathFind::subList(Block<String> &subDirList,String pathEntry)
{
	subDirList.remove();
	String entryString;

	pathEntry+=mBackSlashString;
	pathEntry+=mStarDotStarString;
	if(mFindData.findFirst(pathEntry,FindData::FileDirectory))
	{
		entryString=mFindData.fileName();
		if(isDirectory(mFindData)){entryString.lower();subDirList.insert(&entryString);}
		while(mFindData.findNext())
		{
			entryString=mFindData.fileName();
			if(isDirectory(mFindData)){entryString.lower();subDirList.insert(&entryString);}
		}
	}
}

WORD PathFind::canTranscend(String &pathEntry)
{
  FindData findData;
	char *lpStr;

	if(!findData.findFirst(pathEntry)||findData.attributes()&FindData::FileDirectory)
	{
		String tempString(pathEntry);
		if(*((char*)tempString+tempString.length())!=BackSlash&&*((char*)tempString+tempString.length())!=ForwardSlash)tempString+=mBackSlashString;
		tempString+=mStarDotStarString;
		if(mFindData.findFirst(tempString,FindData::FileDirectory))
		{
			if(isDirectory(mFindData))return TRUE;
			while(mFindData.findNext())if(isDirectory(mFindData))return TRUE;
		}
		return FALSE;
	}
	lpStr=::strchr(pathEntry,Dot);
	*lpStr=BackSlash;
	return FALSE;
}

void PathFind::fixupPathName(String &pathEntry)
{
	char *lpStr;
	if(0==(lpStr=::strchr(pathEntry,Dot)))
  {
		if(*((char*)pathEntry+pathEntry.length())!=BackSlash&&*((char*)pathEntry+pathEntry.length())!=ForwardSlash)pathEntry+=mBackSlashString;
		return;
	}
	*lpStr=BackSlash;
  return;
}

void PathFind::insertPath(String &pathFileSpec)const
{
  String currentDirectory;
	DiskInfo diskInfo;
	diskInfo.getCurrentDirectory(currentDirectory);
	currentDirectory+=mBackSlashString;
	pathFileSpec.insert(currentDirectory);
}

WORD PathFind::isDirectory(FindData &findData)
{
	String tempString;

	if(FindData::FileDirectory&findData.attributes())
	{
		tempString=findData.fileName();
		if(!(tempString==mUpDirString)&&!(tempString==mCurrDirString))return TRUE;
	}
	return FALSE;
}

WORD PathFind::getPathBlock(void)
{
	String strCopyPath;
	char *lpPath;
	char *lpTemp;

  strCopyPath=::getenv((LPSTR)mPathString);
	if(strCopyPath.isNull())return FALSE;
	lpPath=(char*)strCopyPath;
  if(0==(lpTemp=::strtok(lpPath,mSemicolonString)))return FALSE;
	mPathEntry.remove();
	while(TRUE)
	{
		mPathEntry.insert(&String(lpTemp));
		if(0==(lpTemp=::strtok(0,mSemicolonString)))break;
	}
	return (mIsOkay=TRUE);
}

WORD PathFind::getWinDir(String &winDirString)
{
	char *lpPath;

  if(0==(lpPath=::getenv((LPSTR)mWinDirString)))
  {
		mWinDirString.upper();
		if(0==(lpPath=::getenv((LPSTR)mWinDirString)))return FALSE;
		mWinDirString.lower();
	}
  winDirString=lpPath;
  return TRUE;
}

WORD PathFind::getCurrDir(String &currDirString)
{
	DiskInfo diskInfo;
	return diskInfo.getCurrentDirectory(currDirString);
}          

WORD PathFind::getWindowsDirectory(String &windowsDirectoryString)
{
  String windowsDirString;

  if(FALSE==(::GetWindowsDirectory(windowsDirString,String::MaxString)))return FALSE;
  windowsDirectoryString=windowsDirString;
  return TRUE;
}

WORD PathFind::getSystemDirectory(String &systemDirectoryString)
{
  String systemDirString;

  if(FALSE==(::GetSystemDirectory(systemDirString,String::MaxString)))return FALSE;
  systemDirectoryString=systemDirString;
  return TRUE;
}

BOOL PathFind::getWindowsTempDirectory(String &windowsTempDirectory)
{
  String windowsTempDir;

	if(FALSE==(::GetTempPath(String::MaxString,(char*)windowsTempDir)))return FALSE;
	windowsTempDirectory=windowsTempDir;
	return TRUE;
}

BOOL PathFind::getTempFileName(String &strPathTempFileName,const String &strPrefix)
{
  String strPathTempDir;

	getWindowsTempDirectory(strPathTempDir);
	strPathTempFileName=::_tempnam(strPathTempDir,strPrefix.isNull()?0:(char*)(String&)strPrefix);
	return !(strPathTempFileName.isNull());
}




