#include "StdAfx.h"
#include "alias.h"
#include "dir.h"
#include "connection.h"
#include "StringCompare.h"

CAlias::CAlias()
{
	m_isMove = 0;
	m_isDirectory = 0;
}

CAlias::CAlias(CString url,CString targetHost,CConfigAccess serverSetting)
{
	m_targetHost = targetHost;
	m_serverSetting = serverSetting;
	m_pathSetting = m_serverSetting.GetAccess("Path");
	m_indexSetting = m_serverSetting.GetAccess("Index");
	m_url = url;
	m_isMove = 0;
	m_isDirectory = 0;

	//	高速化のため、ロック
	LOCK_CONFIG(serverSetting);

	//	パス情報の取得
	m_pathInfo = FindPathInfo(m_url,targetHost);
	FindTarget(m_url);
	CheckIndexFile();
	CheckExtraPath();
}

CAlias::~CAlias(void)
{
}

/*!
 *	パス情報の取得
 *
 *	@return		パス情報
 */
CConfigAccess CAlias::GetPathInfo()
{
	return(m_pathInfo);
}

/*!
 *	パス情報のOptions取得
 *
 *	@return		パス情報
 */
CConfigAccess CAlias::GetPathOptions()
{
	return(m_pathInfo.GetAccess("Options"));
}

/*!
 *	ターゲットを取得
 *
 *	@return		パス情報
 */
CString CAlias::GetTarget()
{
	return(m_target);
}

/*!
 *	ターゲットを取得
 *
 *	@return		パス情報
 */
CString CAlias::GetExtraTarget()
{
	return(m_extraTarget);
}

/*!
 *	エクストラパスを取得
 *
 *	@return		パス情報
 */
CString CAlias::GetExtraPath()
{
	return(m_extraPath);
}

/*!
 *	ホストを取得
 *
 *	@return		パス情報
 */
CString CAlias::GetTargetHost()
{
	return(m_targetHost);
}

/*!
 *	移動先を取得
 *
 *	@return		URL情報
 */
CString CAlias::GetMoveTo()
{
	return(m_moveTo);
}

/*!
 *	移動の必要があるか取得
 *
 *	@return		1:移動
 */
int CAlias::IsMove()
{
	return(m_isMove);
}

/*!
 *	ディレクトリ？
 *
 *	@return		1:ディレクトリ
 */
int CAlias::IsDirectory()
{
	return(m_isDirectory);
}

/*!
 *	存在するの？
 *
 *	@return		1:存在
 */
int CAlias::IsExist()
{
	if(m_isMove)
		return(1);

	if(CDir::FileExist(m_target) != CDir::FILE_TYPE_NOTFOUND)
		return(1);

	return(0);
}

/*!
 *	エクストラパスがあるのか？
 *
 *	@return		1:存在
 */
int	CAlias::IsExtarExist()
{
	return(!m_extraPath.IsEmpty());
}


/*!
 *	隠しファイル？
 *
 *	@return		1:存在
 */
int CAlias::IsHidden()
{
	if(IsExist() == 0)
		return(0);

	int	attr = CDir::GetFileAttribute(m_target);
	if(attr != -1 && (attr & CDir::FILE_ATTR_HIDDEN))
		return(1);

	return(0);
}

/*!
 *	インデックスファイルは？
 *
 *	@return		1:存在
 */
int CAlias::CheckIndexFile()
{
	if(IsDirectory() && !m_isMove)
	{
		CConfigAccess	index = m_serverSetting.GetAccess("Index");
		CStringArray	keyList;
		int i,len = index.GetAllKey(keyList);

		for(i=0;i<len;i++)
		{
			if(CDir::FileExist(m_target + index.GetConfig(keyList[i],"")) == CDir::FILE_TYPE_FILE)
			{
				m_isMove = 1;
				m_moveTo = index.GetConfig(keyList[i],"");
				return(1);
			}
		}
	}

	return(0);
}

/*!
 *	パスの検索
 *
 *　一致した情報の中で、最も長いサーバパスを持つ情報を返す
 *	同じサーバパスが複数ある場合は、最も長いホスト名を持つ情報を返す
 *
 *	@return		パス情報
 */
CConfigAccess CAlias::FindPathInfo(CString url,CString targetHost)
{
	//	バーチャルホストを処理
	CStringArray	hostList;
	FindVirtualHost(targetHost,hostList);

	//	パスを処理
	CStringArray	hitList;
	FindPath(url,hostList,hitList);

	//	複数一致した場合、最も一致するパス情報を取得
	int len = (int)hitList.GetSize();
	int maxIndex = 0;
	if(len > 1)
	{
		int	maxHit = 0;
		int urlLen = url.GetLength();
		for(int i=0;i<len;i++)
		{
			CConfigAccess	compPath = m_pathSetting.GetAccess(hitList[i]);
			CString			hostName = compPath.GetConfig("VirtualHost","*");
			int				hostNameLen = hostName.GetLength();

			if(maxHit < hostNameLen)
			{
				maxHit = hostNameLen;
				maxIndex = i;
			}
		}
	}

	return m_pathSetting.GetAccess(hitList[maxIndex]);
}


/*!
 *	最も長く一致するパスを検索
 *
 *	@param allNode	ノード名
 *	@param nodeList	ノード名
 */
void CAlias::FindPath(CString url,CStringArray &allNode,CStringArray &nodeList)
{
	int len = (int)allNode.GetSize();
	nodeList.RemoveAll();

	//	一致するパスを検索する
	CStringArray	machNode;
	int urlLen = url.GetLength();
	int	maxHit = 0;
	for(int i=0;i<len;i++)
	{
		CConfigAccess	compPath = m_pathSetting.GetAccess(allNode[i]);
		CString			serverPath = compPath.GetConfig("ServerPath","/");
		int				serverPathLen = serverPath.GetLength();

		if(urlLen >= serverPathLen)
		{
			if(serverPath.CompareNoCase(url.Left(serverPathLen)) == 0)
			{
				if(maxHit <= serverPathLen)
				{	
					maxHit = serverPathLen;
					machNode.Add(allNode[i]);
				}
			}
		}
		else if(urlLen + 1 == serverPathLen)
		{
			//	'/'の無い、ディレクトリ指定
			if(serverPath.CompareNoCase(url + "/") == 0)
			{
				if(maxHit <= serverPathLen)
				{	
					maxHit = serverPathLen;
					machNode.Add(allNode[i]);
				}
			}
		}
	}

	//	見つからなければエラー
	if(machNode.GetSize() == 0)
		throw CServerFatalException("あなたのアクセスしたURLは、このサーバの管理下ではありません");

	//	複数一致した場合、一致したパスの中で、長さの短い物を排除
	len = (int)machNode.GetSize();
	if(len >1)
	{
		for(int i=0;i<len;i++)
		{
			CConfigAccess	compPath = m_pathSetting.GetAccess(machNode[i]);
			CString			serverPath = compPath.GetConfig("ServerPath","/");
			int				serverPathLen = serverPath.GetLength();

			if(maxHit <= serverPathLen)
				nodeList.Add(machNode[i]);
		}
	}
	else
	{
		nodeList.Add(machNode[0]);
	}
}


/*!
 *	バーチャルホスト検索
 *
 *	@param nodeList	ノード名
 */
void CAlias::FindVirtualHost(CString targetHost,CStringArray &nodeList)
{
	CStringArray	allNode;
	int len = m_pathSetting.GetAllSubNode(allNode);
	nodeList.RemoveAll();

	//	パス設定が無い
	if(len == 0)
		throw CServerFatalException("パス設定が存在しません、設定してください！");

	//	まず、バーチャルホストを処理
	if(targetHost.IsEmpty())
		targetHost = "*";
	for(int i=0;i<len;i++)
	{
		CConfigAccess	compPath = m_pathSetting.GetAccess(allNode[i]);
		CString			hostName = compPath.GetConfig("VirtualHost","*");
		int				hostNameLen = hostName.GetLength();

		//	一致すれば、Hitリストに追加
		if(hostName == "*" || CStringCompare::WildCompare(hostName,targetHost))
			nodeList.Add(allNode[i]);
	}

	if(nodeList.GetSize() == 0)
		throw CServerFatalException("あなたのアクセスしたホスト名(URL)は、このサーバの管理下ではありません");
}

/*!
 *	パスの変換
 *
 *	@param	url	URL
 *	@return		パス情報
 */
void CAlias::FindTarget(CString url)
{
	CString serverPath = m_pathInfo.GetConfig("ServerPath","/");
	int urlLen = url.GetLength();
	int serverPathLen = serverPath.GetLength();

	CString	localPath = m_pathInfo.GetConfig("LocalPath","Z:\\");

	//	転送？
	if(m_pathInfo.GetConfig("Forward","") != "")
	{
		if(urlLen > serverPathLen)
		{
			CString sub = url.Mid(serverPath.GetLength());
			m_moveTo = m_pathInfo.GetConfig("Forward","") + sub;
		}
		else
		{
			m_moveTo = m_pathInfo.GetConfig("Forward","");
		}
		m_isMove = 1;
	}
	else
	{
		if(urlLen > serverPathLen)
		{
			CString sub = url.Mid(serverPath.GetLength());
			sub.Replace('/','\\');

			m_target = localPath + sub;

			//	ディレクトリ?
			if(CDir::CheckBackSlash(m_target))
				m_isDirectory = 1;
			else
			{
				//	ディレクトリで、移動の必要あり？
				if(CDir::FileExist(m_target + "\\") == CDir::FILE_TYPE_DIRECTORY)
				{
					m_isMove = 1;
					m_isDirectory = 1;

					m_moveTo = url + "/";
					m_target += "\\";
				}
			}
		}
		else if(urlLen == serverPathLen)
		{
			m_target = localPath;
			m_isDirectory = 1;
		}
		else
		{
			m_isMove = 1;
			m_isDirectory = 1;

			m_moveTo = serverPath;
			m_target = localPath;
		}
	}
}


/*!
 *	エキストラパスの存在を調べる
 *
 *	@return		1:エキストラパスあり、0:なし
 */
int CAlias::CheckExtraPath()
{
	m_extraPath = "";
	m_extraTarget = "";

	//	そもそもある
	if(IsExist() || IsMove() || IsDirectory())
		return(0);

	//	ベースパス取得
	CString	localPath = m_pathInfo.GetConfig("LocalPath","Z:\\");
	CString	target = CDir::GetUpDir(GetTarget());

	//	上へ上っていく
	for(int i=0;i<500;i++)
	{
		//	見つからない
		if(target.GetLength() <= localPath.GetLength())
			break;

		//	見つかった
		if(CDir::FileExist(target) == CDir::FILE_TYPE_FILE)
		{
			m_extraPath = m_target.Mid(target.GetLength());
			m_extraTarget = target;
			return(1);
		}
	}

	return(0);
}
