#include "StdAfx.h"
#include "resource.h"		// メイン シンボル
#include "directoryresponse.h"
#include "connection.h"
#include "UrlUtility.h"

#define	MAX_LINE	2048



CDirectoryResponse::CDirectoryResponse(CServer *server,CWorkspaceAccess context,CRequest request,CAlias alias)
: CNormalResponse(server,context,request,alias)
{
	//	ディレクトリ表示は許可されているのか？
	if(alias.GetPathOptions().GetConfig("EnableIndex",0) == 0)
		throw new CSystemResponse(server,context,"インデックス表示は許可されていません",403);

	//	実は無いとか
	if(alias.IsExist()==0)
		throw new CSystemResponse(server,context,"指定されたディレクトリは存在しません",404);

	//	メソッドはGET?
	if(request.GetMethod() != "GET")
		throw new CSystemResponse(server,context,"対応していないメソッドです",405);

	m_done = 0;
}

CDirectoryResponse::~CDirectoryResponse(void)
{
}

/*
	レスポンス生成
*/
void CDirectoryResponse::CreateResponse()
{
	//	レスポンスコード
	SetResponseCode(200);	//OK

	CMimeTypeMgr	mimeTypes = m_server->GetCMimeTypeMgr();
	CBuffer			dirHtml(0);
	char			stringBuf[MAX_LINE];
	CString			iconPath;
	int				sortMode = -1;
	CString			query = m_request.GetQuery();

	if(query == "name")
		sortMode = 0;
	else if(query == "modified")
		sortMode = 1;
	else if(query == "size")
		sortMode = 2;

	//	ディレクトリリストを取得
	CFileItemArray	dirList;
	GetDirectoryList(dirList,sortMode);

	//	UP
	if(m_requestInfo.GetConfig("Object","") != "/")
	{
		iconPath =  mimeTypes.GetIconPathByName("..");
		_snprintf_s(stringBuf,MAX_LINE,MAX_LINE,"<IMG SRC=\"%s\"> <A HREF=\"../\">%-70s -                        -  \n",
			iconPath,"Parent Directory</A>");
		dirHtml += stringBuf;
	}

	//	ディレクトリ
	iconPath = mimeTypes.GetIconPathByName("^^DIRECTORY^^");
	for(int i=0;i<dirList.GetSize();i++)
	{
		if(dirList[i].m_name != "." && dirList[i].m_name != "..")
		{
			_snprintf_s(stringBuf,MAX_LINE,MAX_LINE,"<IMG SRC=\"%s\"> <A HREF=\"%s/\">%-70s%s       -  \n",
				iconPath,CUrlUtility::EncodeUrl(dirList[i].m_name),dirList[i].m_name + "/</A>",
					dirList[i].m_lastUpdate.Format("%Y/%m/%d %H:%M:%S"));
			dirHtml += stringBuf;
		}
	}


	//	リンクリストを取得
	CFileItemArray	linkList;
	GetLinkList(linkList,sortMode);
	iconPath = mimeTypes.GetIconPathByName("^^LINK^^");
	for(int i=0;i<linkList.GetSize();i++)
	{
		_snprintf_s(stringBuf,MAX_LINE,MAX_LINE,"<IMG SRC=\"%s\"> <A HREF=\"%s/\">%-70s -                        -  \n",
			iconPath,CUrlUtility::EncodeUrl(linkList[i].m_name),linkList[i].m_name + "/</A>");
		dirHtml += stringBuf;
	}


	//	ファイルリストを取得
	CFileItemArray	fileList;
	GetFileList(fileList,sortMode);
	for(int i=0;i<fileList.GetSize();i++)
	{
		if(fileList[i].m_name.CompareNoCase(_T("DirectoryList.html")))
		{
			iconPath = mimeTypes.GetIconPathByName(fileList[i].m_name);

			if(fileList[i].m_size < 10240)
			{
				_snprintf_s(stringBuf,MAX_LINE,MAX_LINE,"<IMG SRC=\"%s\"> <A HREF=\"%s\">%-70s%s      %d  \n",
						iconPath,CUrlUtility::EncodeUrl(fileList[i].m_name),fileList[i].m_name + "</A>",
						fileList[i].m_lastUpdate.Format("%Y/%m/%d %H:%M:%S"),fileList[i].m_size);
			}
			else if(fileList[i].m_size < 1048576 * 10)
			{
				_snprintf_s(stringBuf,MAX_LINE,MAX_LINE,"<IMG SRC=\"%s\"> <A HREF=\"%s\">%-70s%s      %dK  \n",
						iconPath,CUrlUtility::EncodeUrl(fileList[i].m_name),fileList[i].m_name + "</A>",
						fileList[i].m_lastUpdate.Format("%Y/%m/%d %H:%M:%S"),fileList[i].m_size/1024);
			}
			else
			{
				_snprintf_s(stringBuf,MAX_LINE,MAX_LINE,"<IMG SRC=\"%s\"> <A HREF=\"%s\">%-70s%s      %dM  \n",
						iconPath,CUrlUtility::EncodeUrl(fileList[i].m_name),fileList[i].m_name + "</A>",
						fileList[i].m_lastUpdate.Format("%Y/%m/%d %H:%M:%S"),fileList[i].m_size/1048576);
			}
			dirHtml += stringBuf;
		}
	}

	//	カレントからテンプレートをロード
	int ret = m_body.LoadFromFile(m_alias.GetTarget() + "DirectoryList.html");

	//	無いなら、デフォルト
	if(ret != 0)
	{
		//	HTMLファイルのディレクトリ取得
		CString path = m_setting.GetConfig("Html\\HtmlFileDirectory","%ServerRoot%Html\\");
		ret = m_body.LoadFromFile(path + "DirectoryList.html");
	}

	//	さらに無いなら、リソースから
	if(ret != 0)
		ret = m_body.LoadFromResource(IDR_DIRECTORY);

	//	ロードできない場合は、あぼーん
	if(ret != 0)
		throw CServerFatalException("HTMLデータのロードに失敗しました、リソースが破壊されているか、システムエラーです");

	//	置き換え
	m_body.SwapKey(m_context);
	m_body.SwapKey(m_serverInfo);
	m_body.SwapKey(m_requestInfo);
	m_body.SwapKey(m_responseInfo);
	m_body.SwapKey("FileList",dirHtml);

}


/*!
	レスポンスサイズの取得
*/
__int64 CDirectoryResponse::GetResponseSize()
{
	return(m_body.m_html.GetLength());
}

/*!
	レスポンスの取得
*/
int CDirectoryResponse::GetNextData(CBuffer &data)
{
	if(m_done)
	{
		return(0);
	}
	else
	{
		if(m_body.m_html.GetLength()==0)
			throw CServerFatalException("HTMLデータのロードに失敗しました、システムエラーです");

		m_done = 1;
		data = m_body.m_html;
		return(data.GetSize());
	}
}


/*!
 *	リンクリストの取得
 *
 *	@return		0:正常終了
 */
int CDirectoryResponse::GetLinkList(CFileItemArray & list, int sortMode)
{
	list.RemoveAll();

	//	パス設定を取得
	CWorkspaceAccess	pathSetting = m_setting.GetAccess("Path");

	//	検索
	CString			curPath = m_requestInfo.GetConfig("Object","");
	int				curPathLen = curPath.GetLength();
	CStringArray	nodeList;
	int len = pathSetting.GetAllSubNode(nodeList);

	for(int i=0;i<len;i++)
	{
		CWorkspaceAccess	compPath = pathSetting.GetAccess(nodeList[i]);
		CString			serverPath = compPath.GetConfig("ServerPath","/");
		serverPath = serverPath.Mid(0,serverPath.GetLength()-1);

		if(curPathLen >= serverPath.GetLength())
			continue;

		//	切り出し
		int index = serverPath.ReverseFind('/');
		if(index == -1)
			continue;

		//	有効か？
		if(curPath.CompareNoCase(serverPath.Mid(0,index + 1))==0)
		{
			CFileItem	add;
			add.m_name = serverPath.Mid(index + 1);
			add.m_sortMode = sortMode;
			add.m_size = 0;
			list.Add(add);
		}
	}

	//	ソートが有効
	if(sortMode != -1)
		list.Sort();

	return 0;
}



/*!
 *	ディレクトリリストの取得
 *
 *	@return		0:正常終了
 */
int CDirectoryResponse::GetDirectoryList(CFileItemArray & list, int sortMode)
{
	list.RemoveAll();

	int				showHidden = m_alias.GetPathOptions().GetConfig("EnableHiddenFile",0);
	int				done=1;
	CFileFind		find;

	if(find.FindFile(m_alias.GetTarget() + "*.*"))
	{
		while(done)
		{
			done=find.FindNextFile();

			if(find.IsDots())
				continue;

			if(find.IsHidden() && showHidden == 0)
				continue;

			if(find.IsDirectory())
			{
				CFileItem	add;
				add.m_name = find.GetFileName();
				add.m_sortMode = sortMode;
				add.m_size = 0;
				find.GetLastWriteTime(add.m_lastUpdate);
				list.Add(add);
			}
		}
	}
	find.Close();

	//	ソートが有効
	if(sortMode != -1)
		list.Sort();

	return 0;
}


/*!
 *	ファイルリストの取得
 *
 *	@return		0:正常終了
 */
int CDirectoryResponse::GetFileList(CFileItemArray & list, int sortMode)
{
	list.RemoveAll();

	int				showHidden = m_alias.GetPathOptions().GetConfig("EnableHiddenFile",0);
	int				done=1;
	CFileFind		find;

	if(find.FindFile(m_alias.GetTarget() + "*.*"))
	{
		while(done)
		{
			done=find.FindNextFile();

			if(find.IsDirectory())
				continue;

			if(find.IsHidden() && showHidden == 0)
				continue;

			CFileItem	add;
			add.m_name = find.GetFileName();
			add.m_sortMode = sortMode;
			add.m_size = find.GetLength();
			find.GetLastWriteTime(add.m_lastUpdate);
			list.Add(add);

		}
	}
	find.Close();

	//	ソートが有効
	if(sortMode != -1)
		list.Sort();

	return 0;
}

/*!
 *	ディレクトリの作成時間の取得
 *
 *	@return		時刻
 */
CTime CDirectoryResponse::GetTargetDate()
{
	int				done=1;
	CFileFind		find;
	CTime			ret=CTime::GetCurrentTime();

	if(find.FindFile(m_alias.GetTarget() + "*.*"))
	{
		while(done)
		{
			done=find.FindNextFile();

			if(find.GetFileName() == ".")
			{
				find.GetLastWriteTime(ret);
				break;
			}

		}
	}
	find.Close();


	return ret;
}

