// Launcher.cpp: CLauncher クラスのインプリメンテーション
//
//////////////////////////////////////////////////////////////////////
//		2004-06-09	b040606 (3421)初期設定値の改善(moralog)

#define ExeCommon
#include "stdafx.h"
#include "shitarabian.h"
#include "Launcher.h"
#include "ExeCommon.h"
#include "Common.h"
#include <process.h>
#include "SettingPath.h"
#include "ShitarabianDoc.h"
#include "MainFrm.h"
#include "Selection.h"
#include "ShitarabianView.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//-----------------------------------------------------------------------------
// スタティックメンバの初期化
//-----------------------------------------------------------------------------
CString		CLauncher::m_strKeywordDocPath		= _T("&[文書パス]");
CString		CLauncher::m_strKeywordDocName		= _T("&[文書タイトル]");
CString		CLauncher::m_strKeywordDocExt		= _T("&[文書拡張子]");
CString		CLauncher::m_strKeywordWindowHandle	= _T("&[したらびあんウィンドウ]");
// ▼ (未実装機能削除) BGN 2004.06.09 (moralog)
// ▽ original BGN
//CString		CLauncher::m_strKeywordMessageID	= _T("&[したらびあんメッセージID]");
// △ original END
// ▲ (未実装機能削除) END
CString		CLauncher::m_strKeywordShitarabianFolder	= _T("&[したらびあんフォルダ]");
CString		CLauncher::m_strKeywordShitarabianCurrentDoc = _T("&[したらびあん編集中文書]");
CString		CLauncher::m_strKeywordShitarabianSelection = _T("&[したらびあん選択文字列]");

static CString	f_strTmpFileTitle = _T( "_temporary" );

//////////////////////////////////////////////////////////////////////
// 構築/消滅
//////////////////////////////////////////////////////////////////////

CLauncher::CLauncher()
: m_strIniFilename( _T("launch.ini") )
{

}

CLauncher::~CLauncher()
{
	DestroyButtonz( NULL );
}


CLauncher*	CLauncher::GetInstance()
{
	static	CLauncher	s_Launcher;
	return( &s_Launcher );
}

// 利用開始処理
BOOL	CLauncher::CreateButtonz(
	CToolBar*	pParent				// ボタン構築ツールバー先 [-] (-) :-
)
{
	// ボタン大きさ調整
	CSize	sizeBitmap( 17, 19 );
	pParent->SetSizes(
		CSize( 24, 26 ),
		sizeBitmap
	);

// 第６６章 ツールチップを付ける別の方法 
// http://www.kumei.ne.jp/c_lang/sdk/sdk_66.htm
	// ツールチップを作る ★★破棄してないけど
	HWND hToolTip = CreateWindowEx(
				0,  //拡張ウィンドウスタイル
				TOOLTIPS_CLASS, //クラスネーム
				NULL, //ウィンドウネーム
				TTS_ALWAYSTIP, // ウィンドウスタイル
				CW_USEDEFAULT, // Ｘ座標
				CW_USEDEFAULT, // Ｙ座標
				CW_USEDEFAULT, // 幅
				CW_USEDEFAULT, // 高さ
				pParent->m_hWnd, // 親ウィンドウのハンドル
				NULL,			// メニューハンドル
				::AfxGetResourceHandle(),	// インスタンスハンドル
				NULL);		 // WM_CREATEデータ

	long idxLaunch;
	for ( idxLaunch=0 ; idxLaunch<m_aLaunchDefinez.GetSize() ; idxLaunch++ )
	if ( m_aLaunchDefinez[ idxLaunch ].m_bEnable )
	{
		// ビットマップの取得
		HBITMAP hBmp = PrepareBitmap(
			m_aLaunchDefinez[ idxLaunch ].m_strIconPathName,
			m_aLaunchDefinez[ idxLaunch ].m_idxIcon,
			sizeBitmap
		);

		// ボタンの追加
		long	idCommand = ::UniqueCommandID();
		{
			// ビットマップの登録
			TBADDBITMAP tb;
			tb.hInst = NULL;
			tb.nID = (int)hBmp;
			long iIndex = pParent->SendMessage( TB_ADDBITMAP , 1 , (LPARAM)&tb);
			
			TBBUTTON	tbButton = { 0, 0, TBSTATE_ENABLED, TBSTYLE_TOOLTIPS, 0 , 0 , 0 };
											// ★★ 引数の型は BYTE だが TBSTYLE_TOOLTIPS は 0x100。なぜだ？下位互換？
			tbButton.idCommand = idCommand;
			tbButton.iBitmap = iIndex;
			pParent->SendMessage( TB_ADDBUTTONS , 1 , (LPARAM) &tbButton);

			// ツールチップ追加
			{
				TOOLINFO ti;
				ti.cbSize = sizeof(TOOLINFO);
				ti.hwnd = pParent->m_hWnd;
				ti.hinst = ::AfxGetResourceHandle();
				ti.uFlags = TTF_SUBCLASS;

				pParent->SendMessage( TB_GETITEMRECT, idCommand, (LPARAM)&ti.rect);
				ti.uId = idCommand;
				ti.lpszText = m_aLaunchDefinez[idxLaunch].m_strButtonName.GetBuffer(m_aLaunchDefinez[idxLaunch].m_strButtonName.GetLength());
				::SendMessage(hToolTip, TTM_ADDTOOL, 0, (LPARAM)&ti);
				m_aLaunchDefinez[idxLaunch].m_strButtonName.ReleaseBuffer();
			}
		}
		m_aLaunchDefinez[ idxLaunch ].m_lCommandID = idCommand;
	}
	pParent->SendMessage( TB_SETTOOLTIPS, (WPARAM)hToolTip, 0);
	::GetMainFrame()->ShowControlBar( pParent, FALSE, 0 );
	::GetMainFrame()->ShowControlBar( pParent, TRUE, 0 );

	return( TRUE );
}

// 破棄処理
BOOL	CLauncher::DestroyButtonz(
	CToolBar*	pParent				// ボタン構築ツールバー先 [-] (-) :-
)
{
	// ボタン自体の破棄
	if ( pParent != NULL )
	{
		long	nButton = pParent->GetToolBarCtrl().GetButtonCount();
		long	idxButton;
		for ( idxButton=nButton-1 ; idxButton>=0 ; idxButton-- )
		{
			pParent->SendMessage( TB_DELETEBUTTON , idxButton , 0 );
		}
	}

	// ランチャ情報の破棄
	m_aLaunchDefinez.RemoveAll();

	return( TRUE );
}


// ボタン押下ハンドラ
BOOL	CLauncher::CommandHandler(
	long	idCommand				// コマンドID [メッセージID] (-) :-
)
{
	long idxLaunch;
	for ( idxLaunch=0 ; idxLaunch<m_aLaunchDefinez.GetSize() ; idxLaunch++ )
	{
		if ( m_aLaunchDefinez[ idxLaunch ].m_lCommandID == idCommand )
		{
			TRACE( _T("ランチャー> %s\n"), m_aLaunchDefinez[ idxLaunch ].m_strCommandLine );

			// キーワード展開
			CString		strCommandLine = m_aLaunchDefinez[ idxLaunch ].m_strCommandLine;
			{

				CShitarabianDoc*	pDoc;
				pDoc = ::GetDocument();

				CString		strPathName = pDoc->GetPathName();
				int	idxLastSlash = strPathName.ReverseFind( '\\' );
				int	idxLastDot = strPathName.ReverseFind( '.' );

				strCommandLine.Replace(
					m_strKeywordDocPath,
					strPathName.Left( idxLastSlash )	// ★★印刷のほうは パス末尾に \ がつくのだがとりさったほうがよいのでは
				);

				strCommandLine.Replace(
					m_strKeywordDocName,
					strPathName.Mid( idxLastSlash+1, idxLastDot-idxLastSlash-1 )
				);

				strCommandLine.Replace(
					m_strKeywordDocExt,
					strPathName.Mid( idxLastDot+1 )
				);

				CString		strWindow;
				strWindow.Format("%d", (::GetMainFrame())->m_hWnd );
				strCommandLine.Replace(
					m_strKeywordWindowHandle,
					strWindow
				);

// ▼ (未実装機能削除) BGN 2004.06.09 (moralog)
// ▽ original BGN
//				CString		strMessageID;
//				strMessageID.Format("%d", 0 );
//				strCommandLine.Replace(
//					m_strKeywordMessageID,
//					strMessageID
//				);
// △ original END
// ▲ (未実装機能削除) END

				CString		strShitarabianFolder;
				strShitarabianFolder = CSettingPath::GetInstance()->GetShitarabianFolderPath();
				strCommandLine.Replace(
					m_strKeywordShitarabianFolder,
					strShitarabianFolder
				);

				// 編集中文書
				{
					// 編集中文書の拡張子を使用するが拡張子が無いときはtxtとみなす。
					CString		strCurrentDocFile;
					CString		strExt = ::ExtFromPathName((CString)pDoc->GetPathName());
					if ( strExt.IsEmpty() )
					{
						strExt = "txt";
					}
					strCurrentDocFile.Format(
						"%s\\%s.%s",
						strShitarabianFolder,
						f_strTmpFileTitle,
						strExt
					);

					// ファイルの保存
					TRY
					{
						CFile	File( strCurrentDocFile, CFile::modeWrite|CFile::modeCreate );
						CArchive	ar( &File, CArchive::store );
						pDoc->Serialize( ar );
					}
					CATCH( CFileException, e )
					{
						// ERROR
						::ErrorLog( _T("テンポラリファイルの保存に失敗"), _T("CLauncher::CommandHandler") );
					}
					END_CATCH

					strCommandLine.Replace(
						m_strKeywordShitarabianCurrentDoc,
						strCurrentDocFile
					);
				}

				// 選択文字列
				((CShitarabianView*)(::GetMainFrame()->GetActiveView()))->SelectMagicRod();
				CString		strSelection;
				strSelection.Format("%s", pDoc->GetSelection()->GetSelectedText() );
				strCommandLine.Replace(
					m_strKeywordShitarabianSelection,
					strSelection
				);
			}
			TRACE( _T("ランチャー> %s\n"), strCommandLine );

			// コマンドラインを空白で分割
			CStringArray	aLinez;
			CString			strBlank( _T(" ") );
			long	nLine = ::StringToArrayWithQuoteCare(
				strCommandLine,
				&aLinez,
				strBlank
			);

			// デフォルトのアプリで開く
			if ( m_aLaunchDefinez[ idxLaunch ].m_bDefaultOpen )
			{
				// 存在確認
				CFileStatus	Status;
				BOOL		bExists = CFile::GetStatus( strCommandLine, Status );
				if ( bExists && Status.m_attribute & CFile::directory )
				{
					// フォルダの場合はIEで開く
					_spawnlp( _P_NOWAIT, "explorer.exe", "explorer.exe", strCommandLine, NULL );
				}
				else
				{
					// ファイルの場合はアプリで開く
					::ShellExecute(
						HWND_DESKTOP, NULL,
						strCommandLine,
						NULL, NULL, SW_SHOWNORMAL
					);
				}
				return( TRUE );
			}

			if ( nLine > 0 )
			{
				// 実行ファイルを囲むクオーテーションを除去
				CString	strExe = ::DeQuoteString( aLinez[ 0 ] );
				aLinez[ 0 ] = strExe;

				LPCTSTR*	astr = new LPCTSTR[ nLine+1 ];
				{
					// spawn 引数組み立て
					long	idxToken;
					for ( idxToken=0 ; idxToken<nLine ; idxToken++ )
					{
						TRACE( "token%d [%s]\n", idxToken, aLinez[ idxToken ] );
						astr[ idxToken ] = (LPCTSTR)( aLinez[ idxToken ] );
					}
					astr[ nLine ] = NULL;

					// プロセスを立ち上げ
					_spawnvp( _P_NOWAIT, astr[0], astr );
				}
				delete [] astr;
			}
			return( TRUE );
		}
	}
	return( FALSE );
}


// ビットマップの用意
HBITMAP CLauncher::PrepareBitmap(
	LPCTSTR		strIconPathName,	// アイコンを保持する実効ファイルパス [-] (-) :-
	long		idxIcon,				// アイコン番号 [-] (-) :-
	CSize		sizeBitmap
)
{
	CBitmap		Bitmap;
	{
		// ビットマップにアイコン描画
		HDC hdc = ::GetDC( NULL );
		CDC*	pdcScreen = CDC::FromHandle( hdc );
		{
			// ボタン大きさのビットマップを確保
			Bitmap.CreateCompatibleBitmap(
				pdcScreen,
				sizeBitmap.cx,
				sizeBitmap.cy
			);

			// ビットマップにアイコンを描画
			CDC	dc;
			dc.CreateCompatibleDC( pdcScreen );
			CBitmap*	pbmpOld = dc.SelectObject( &Bitmap );
			{
				dc.FillSolidRect( 0, 0, sizeBitmap.cx, sizeBitmap.cy, GetSysColor(COLOR_BTNFACE) );
				dc.SetMapMode( MM_TEXT );

				// アイコンの描画
				::DrawIcon(
					&dc,
					CRect( 0, 0, sizeBitmap.cx, sizeBitmap.cy ),
					strIconPathName,
					idxIcon
				);
			}
			dc.SelectObject( pbmpOld );
		}
		::ReleaseDC( NULL, hdc );
	}

	HBITMAP	hbmp = (HBITMAP)Bitmap;
	Bitmap.Detach();

	return( hbmp );
}

BOOL CLauncher::Write()
{
	try
	{
		CString		strFilename = CSettingPath::GetInstance()->GetFolderPath() + m_strIniFilename;
		CStdioFile	file( strFilename, CFile::modeCreate | CFile::modeWrite );

		// バージョンの書きだし
		CString		strVersion;
		strVersion.LoadString( IDS_RELEASE_VERSION );
		file.WriteString( strVersion + "\n" );

		// ランチャ定義の書き出し
		int	idxItem;
		for( idxItem=0 ; idxItem<m_aLaunchDefinez.GetSize() ; idxItem++ )
		{
			file.WriteString( ::QuoteString( m_aLaunchDefinez[idxItem].m_strButtonName ) + "\n" );
			file.WriteString( ::BoolToString( m_aLaunchDefinez[idxItem].m_bEnable ) + "\n" );
			file.WriteString( ::QuoteString( m_aLaunchDefinez[idxItem].m_strIconPathName ) + "\n" );
			file.WriteString( ::LongToString( m_aLaunchDefinez[idxItem].m_idxIcon ) + "\n" );
			file.WriteString( ::QuoteString( m_aLaunchDefinez[idxItem].m_strCommandLine ) + "\n" );
			file.WriteString( ::BoolToString( m_aLaunchDefinez[idxItem].m_bDefaultOpen ) + "\n" );
		}

		return( TRUE );
	}
	catch( CFileException* e )
	{
		e->Delete();
		ErrorLog( "ファイル出力", "CLauncher::Write()" );
		return( FALSE );
	}
}

BOOL CLauncher::Read()
{
	DestroyButtonz( NULL );

	CString		strGeneralFilename = CSettingPath::GetInstance()->GetFolderPath() + m_strIniFilename;

	CFileStatus	status;
	BOOL	bExists = CFile::GetStatus( strGeneralFilename, status );
	if ( !bExists )
	{
		// ファイル自体が無い

		// ボタンを新設
		{
			CLaunchItem		LaunchItem;

			// 新規ウィンドウ
			LaunchItem.m_strButtonName = _T( "新規ウィンドウを開く" );
			LaunchItem.m_bEnable = TRUE;
			LaunchItem.m_strCommandLine.Format( _T("%s\\shitarabian.exe"), this->m_strKeywordShitarabianFolder );
			LaunchItem.m_bDefaultOpen = FALSE;
			LaunchItem.m_idxIcon = 99;
			m_aLaunchDefinez.Add( LaunchItem );

			// backupフォルダを開く
			LaunchItem.m_strButtonName = _T( "backupフォルダを開く" );
			LaunchItem.m_bEnable = TRUE;
			LaunchItem.m_strCommandLine.Format( _T("%s\\backup"), this->m_strKeywordShitarabianFolder );
			LaunchItem.m_bDefaultOpen = TRUE;
			LaunchItem.m_idxIcon = 1;
			m_aLaunchDefinez.Add( LaunchItem );

			// アプリケーションで開く
			LaunchItem.m_strButtonName = _T( "規定のアプリケーションで開く" );
			LaunchItem.m_bEnable = TRUE;
			LaunchItem.m_strCommandLine.Format( _T("%s"), this->m_strKeywordShitarabianCurrentDoc );
			LaunchItem.m_bDefaultOpen = TRUE;
			LaunchItem.m_idxIcon = 2;
			m_aLaunchDefinez.Add( LaunchItem );

			// へぼぺ起動
			LaunchItem.m_strButtonName = _T( "へぼぺ起動" );
			LaunchItem.m_bEnable = TRUE;
// ▼ (3421) BGN 2004.06.09 (moralog) したらびあんとの紐付け
// ▽ original BGN
//			LaunchItem.m_bEnable = FALSE;
//			LaunchItem.m_strCommandLine.Format( _T("%s\\hebope.exe"), this->m_strKeywordShitarabianFolder );
//			LaunchItem.m_bDefaultOpen = FALSE;
//			LaunchItem.m_idxIcon = 0;
// △ original END
			LaunchItem.m_bEnable = TRUE;
			LaunchItem.m_strCommandLine.Format( _T("%s\\hebope.exe \"sample\\hebopesample.hix\" -shitarabian=%s"), this->m_strKeywordShitarabianFolder, this->m_strKeywordWindowHandle );
			LaunchItem.m_bDefaultOpen = FALSE;
			LaunchItem.m_idxIcon = 4;
// ▲ (3421) END
			m_aLaunchDefinez.Add( LaunchItem );

			// 初期値定義を保存
			Write();
		}
		return( FALSE );
	}

	try
	{
		CStdioFile	file( strGeneralFilename, CFile::modeRead | CFile::shareDenyNone );

		BOOL	bSuccess = TRUE;

		// バージョンの読み込み
		CString		strVersion;
		bSuccess = file.ReadString( strVersion );
		if ( !bSuccess )
		{
			return( FALSE );
		}

		// ランチャ定義
		while( TRUE )
		{
			CLaunchItem		LaunchItem;
			CString			strEnable;
			CString			strIcon;
			CString			strIconPathName;
			CString			strButtonName;
			CString			strCommandLine;
			CString			strDefaultOpen;
			bSuccess = file.ReadString( strButtonName );
			bSuccess &= file.ReadString( strEnable );
			bSuccess &= file.ReadString( strIconPathName );
			bSuccess &= file.ReadString( strIcon );
			bSuccess &= file.ReadString( strCommandLine );
			bSuccess &= file.ReadString( strDefaultOpen );
			if ( !bSuccess )
			{
				break;
			}
			LaunchItem.m_strButtonName =::DeQuoteString( strButtonName );
			LaunchItem.m_bEnable = ::StringToBool( strEnable );
			LaunchItem.m_strIconPathName =::DeQuoteString( strIconPathName );
			LaunchItem.m_idxIcon = ::StringToLong( strIcon );
			LaunchItem.m_strCommandLine =::DeQuoteString( strCommandLine );
			LaunchItem.m_bDefaultOpen= ::StringToBool( strDefaultOpen );

			m_aLaunchDefinez.Add( LaunchItem );
		}

		return( TRUE );
	}
	catch( CFileException* e )
	{
		e->Delete();
		ErrorLog( "ファイル入力", "CLauncher::Read()" );
		return( FALSE );
	}

	return( TRUE );
}


CLaunchItem& CLaunchItem::Copy( const CLaunchItem& Src )
{
	m_bEnable			= Src.m_bEnable;
	m_strButtonName		= Src.m_strButtonName;
	m_strIconPathName	= Src.m_strIconPathName;
	m_idxIcon			= Src.m_idxIcon;
	m_strCommandLine	= Src.m_strCommandLine;
	m_lCommandID		= Src.m_lCommandID;
	m_bDefaultOpen		= Src.m_bDefaultOpen;

	return( *this );
}