/*-----------------------------------------------------------------------------
[名称]	ShitarabianViewPrint.cpp
[概要]	Viewクラス（印刷処理）の実装
[備考]	なし
[履歴]	2003-02-25	NC		コメント付加(moralog)
		2003-11-20	b031130 (3198) BOX表示設定反映追加 (dincom)
		2003-12-26  b031228 (3192) 選択領域のみ縦長集約印刷でごみが印刷される修正 (dincom)
-----------------------------------------------------------------------------*/


//-----------------------------------------------------------------------------
// インクルード
//-----------------------------------------------------------------------------
#include "stdafx.h"
#include "Common.h"
#include "ExeCommon.h"
#include "Shitarabian.h"
#include "MainFrm.h"
#include "ShitarabianDoc.h"
#include "ShitarabianView.h"
#include "EditDrawer.h"
#include "GeneralSetting.h"
#include <process.h>
#include "Selection.h"
#include "BoxSelection.h"
#include "FloatingSelection.h"
#include "CommandMultiEdit.h"
#include "Padding.h"
#include "TokenReader.h"
#include "ToolBarManager.h"
#include "ShitarabianPlugInManager.h"



/*-----------------------------------------------------------------------------
[名称]	印刷準備ハンドラ
[機能]	CView::OnPreparePrinting()のヘルプを参照。
[戻値]	CView::OnPreparePrinting()のヘルプを参照。
[備考]	なし
-----------------------------------------------------------------------------*/
BOOL CShitarabianView::OnPreparePrinting(CPrintInfo* pInfo)
{
	// デフォルトの印刷準備
	{
		pInfo->m_nNumPreviewPages = 1;

		// 選択範囲指定を有効に
		CShitarabianDoc*	pDoc = GetDocument();
		CSelection*			pSelection = pDoc->GetSelection();
		if ( pSelection->IsSelected() )
		{
			pInfo->m_pPD->m_pd.Flags |= PD_NOSELECTION;
			pInfo->m_pPD->m_pd.Flags -= PD_NOSELECTION;
			pInfo->m_pPD->m_pd.Flags |= PD_SELECTION;
		}
	}

	BOOL	bSuccess = DoPreparePrinting(pInfo);
	if ( !bSuccess )
	{
		PrintLastErr( "印刷" );
		::ErrorLog(
				_T("印刷失敗（または中止）"),
				_T("CShitarabianView::OnPreparePrinting")
		);
	}

	return bSuccess;
}


/*-----------------------------------------------------------------------------
[名称]	印刷ハンドラ
[機能]	CView::OnPrint()のヘルプを参照。
[戻値]	CView::OnPrint()のヘルプを参照。
[備考]	なし
-----------------------------------------------------------------------------*/
void CShitarabianView::OnPrint(CDC* pDC, CPrintInfo* pInfo) 
{
	CEditDrawer*		pDrawer = CEditDrawer::GetInstance();
	CShitarabianDoc*	pDoc = GetDocument();
	CSelection*			pSelection = pDoc->GetSelection();
	CPrintDefine*		pPrint = CGeneralSetting::GetInstance()->GetPrintDefine();

	int		nPageColumn = 1;
	if ( pPrint->m_bMarge )
	{
		 nPageColumn = pPrint->m_uiMargeCount;
	}

	BOOL	bOnlySelection = pInfo->m_pPD->PrintSelection();

	pDC->SetMapMode( MM_TEXT );

	// 論理座標での印刷範囲
	CSize		sizeTopLeftMarginDP;
	CSize		sizeRightBottomMarginDP;
	{
		sizeTopLeftMarginDP.cx = pPrint->m_lLeftMargin*100;
		sizeTopLeftMarginDP.cy = pPrint->m_lTopMargin*100;
		if ( pPrint->m_bHeader )
		{
			sizeTopLeftMarginDP.cy += pPrint->m_lHeaderHeight *100;
		}
		pDC->HIMETRICtoLP( &sizeTopLeftMarginDP );
		pDC->LPtoDP( &sizeTopLeftMarginDP );

		sizeRightBottomMarginDP.cx = pPrint->m_lRightMargin *100;
		sizeRightBottomMarginDP.cy = pPrint->m_lBottomMargin *100;
		if ( pPrint->m_bFooter )
		{
			sizeRightBottomMarginDP.cy += pPrint->m_lFooterHeight *100;
		}
		pDC->HIMETRICtoLP( &sizeRightBottomMarginDP );
		pDC->LPtoDP( &sizeRightBottomMarginDP );
	}

	// プリンタDCの大きさ
	CSize		sizePrinterPageDP;
	{
		sizePrinterPageDP.cx = pInfo->m_rectDraw.Width() - sizeTopLeftMarginDP.cx - sizeRightBottomMarginDP.cx;
		sizePrinterPageDP.cy = pInfo->m_rectDraw.Height() - sizeTopLeftMarginDP.cy - sizeRightBottomMarginDP.cy;
	}

	// 描画用メモリDCの大きさ
	CSize	sizeMemDCPixel;
	{
		sizeMemDCPixel.cx = pPrint->m_lPrintPixelWidth;
		sizeMemDCPixel.cy = (int)( (double)sizeMemDCPixel.cx * sizePrinterPageDP.cy / sizePrinterPageDP.cx );
		sizeMemDCPixel.cy *= nPageColumn;
	}

	// ページ内行数
	int		nLine = sizeMemDCPixel.cy / (pDrawer->CaretRowToPixel( 1 ) );

	// 印刷する総行数
	int		idxRequestStartLine = 0;
	int		idxRequestEndLine = pDoc->GetLineCount()-1;
	int		nAllLine;
	UINT	nPage;
	{
		if ( bOnlySelection )
		{
			idxRequestStartLine = pSelection->GetSelectedStartRow();
			idxRequestEndLine = pSelection->GetSelectedEndRow();
		}

		nAllLine = idxRequestEndLine - idxRequestStartLine +1;
		nPage = (nAllLine+nLine-1) / nLine;
		if ( pPrint->m_bMarge )
		{
			nPage = (nPage+pPrint->m_uiMargeCount-1)/pPrint->m_uiMargeCount;
		}
		pInfo->SetMaxPage( nPage );
	}

	// ページ内に印刷する行
	int		iStartLine = idxRequestStartLine + (pInfo->m_nCurPage-1) * nLine * nPageColumn;
	int		iEndLine = min( iStartLine+nLine-1, idxRequestEndLine );

	// メモリDC作成
	CDC			MemDC;
	CBitmap		MemBitmap;
	{
		CDC*		pSrcDC = GetDC();
		MemDC.CreateCompatibleDC ( pSrcDC );
		BOOL	bSuccess = MemBitmap.CreateCompatibleBitmap(
			pSrcDC,
			sizeMemDCPixel.cx,
			sizeMemDCPixel.cy
		);
		ReleaseDC( pSrcDC );
		if( !bSuccess )
		{
			::ErrorLog( "メモリDC作成失敗", "CShitarabianView::OnPrint()" );
			return;
		}

		MemDC.SetMapMode( MM_TEXT );
		MemDC.SetBkMode( TRANSPARENT );
		MemDC.SetWindowOrg( 0,0 );
	}

	// 強調表示設定反映？
	BOOL	bEmphasisEnable;
	bEmphasisEnable = CGeneralSetting::GetInstance()->GetEmphasisDefine()->GetEnable();
	CGeneralSetting::GetInstance()->GetEmphasisDefine()->SetEnable(
		pPrint->m_bCareEmphasis
	);

	// ▼ (3198) BGN 2003.11.20 (dincom) BOX表示設定反映有無
	// BOX表示設定反映
	BOOL bBoxCharEnable;
	bBoxCharEnable = CGeneralSetting::GetInstance()->GetBoxCharDefine()->GetEnable();
	CGeneralSetting::GetInstance()->GetBoxCharDefine()->SetEnable(
		pPrint->m_bCareBoxChar
	);
	// ▲ (3198) END 

	// ▼ (3191) BGN 2003.11.25 (dincom) 印刷後の複数行表示色崩れ
	// ▽ 
	// // ドキュメント表示情報の再構築
	// pDoc->ReflectEmphasis();
	// △
	BOOL bEmphasysChange( bEmphasisEnable != pPrint->m_bCareEmphasis );

	if ( bEmphasysChange )
	{
		// ドキュメント表示情報の再構築（時間がかかるので表示色変更のあるときに限定する）
		pDoc->ReflectEmphasis();
		pDoc->AnalizeEmphasisLinez( 0, pDoc->GetLineCount()-1 );
	}
	// ▲ (3191) END

	// ページカラム（集約１列）作成
	int	idxPageColumn;
	for( idxPageColumn=0 ; idxPageColumn<nPageColumn ; idxPageColumn++ )
	{
		CBitmap*	pOldBitmap;
		pOldBitmap = MemDC.SelectObject( &MemBitmap );
		{
			COLORREF	colBack = ::GetBackColor( EMPHASIS_TEXT );
			CRect		rcClient(
				0,0,
				sizeMemDCPixel.cx,
				sizeMemDCPixel.cy
			);
			MemDC.FillSolidRect(
				rcClient,
				colBack
			);

			pDrawer->SetUpdateRect( rcClient );
			// テキストの表示
			PrintColumn(
				&MemDC,
				pInfo,
				sizeMemDCPixel,
				iStartLine,
				iEndLine
			);
// ▼ (ワーニング回避) BGN 2003.12.29 (moralog) warning C4239
			CRect	rcInit(0,0,0,0);
			pDrawer->SetUpdateRect( rcInit );
// ▽ original BGN
//			pDrawer->SetUpdateRect( CRect(0,0,0,0) );
// △ original END
// ▲ (ワーニング回避) END
		}
		MemDC.SelectObject( pOldBitmap );

		// メモリDCからプリンタDCへ転送
		pDC->LPtoDP( &sizeTopLeftMarginDP );
		pDC->SetWindowOrg( 0,0 );

		MemDC.SelectObject( pOldBitmap );

		int		iCaps = pDC->GetDeviceCaps( RASTERCAPS );
		if( iCaps & RC_STRETCHBLT )
		{
			// StretchBlt()できる
			int		iPageColumnWidth = sizePrinterPageDP.cx / nPageColumn;
			CRect rcDst;
			{
 				rcDst.left = pInfo->m_rectDraw.left + sizeTopLeftMarginDP.cx
						+ (iPageColumnWidth * idxPageColumn);
				rcDst.top = pInfo->m_rectDraw.top + sizeTopLeftMarginDP.cy;
				rcDst.right = rcDst.left + iPageColumnWidth;
				rcDst.bottom = rcDst.top + sizePrinterPageDP.cy;
			}

			CRect rcSrc(
				0,
				0,
				sizeMemDCPixel.cx,
				sizeMemDCPixel.cy
			);
			::DIBStretchBlt(
				pDC,
				rcDst,
				&MemDC,
				&MemBitmap,
				rcSrc
			);
		}
		else
		{
			// StretchBlt()できない
			if( iCaps & RC_BITBLT )
			{
				// でかいMemDCを作ってBltするか‥‥
				::ErrorLog( "StretchDIBits()ができないらしい。", "CShitarabianView::OnPrint()" );
				break;
			}
			else
			{
				::ErrorLog( "ていうかこのプリンタ、画像の転送が出来ないし。", "CShitarabianView::OnPrint()" );
				break;
			}
		}
		MemDC.SelectObject( pOldBitmap );

		iStartLine += nLine;
		iEndLine += nLine;
	}

	// 強調表示設定復帰
	CGeneralSetting::GetInstance()->GetEmphasisDefine()->SetEnable(
		bEmphasisEnable
	);

	// ▼ (3198) BGN 2003.11.20 (dincom) BOX表示設定反映有無
	// BOX表示設定復帰
	CGeneralSetting::GetInstance()->GetBoxCharDefine()->SetEnable(
		bBoxCharEnable
	);
	// ▲ (3198) END 

	// ▼ (3191) BGN 2003.11.25 (dincom) 印刷後の複数行表示色崩れ
	// ▽
	// // ドキュメント表示情報の再構築
	// pDoc->ReflectEmphasis();
	// △
	if ( bEmphasysChange )
	{
		// ドキュメント表示情報の再構築（時間がかかるので表示色変更のあるときに限定する）
		pDoc->ReflectEmphasis();
		pDoc->AnalizeEmphasisLinez( 0, pDoc->GetLineCount()-1 );
	}
	// ▼ (3191) END

	// ヘッダ
	if( pPrint->m_bHeader )
	{
		PrintHeader(
			pDC,
			pInfo,
			pPrint,
			sizePrinterPageDP
		);
	}

	// フッタ
	if( pPrint->m_bFooter )
	{
		PrintFooter(
			pDC,
			pInfo,
			pPrint,
			sizePrinterPageDP
		);
	}

	// 全頁印刷済み？
	if ( pInfo->m_nCurPage < nPage )
	{
		pInfo->m_bContinuePrinting = TRUE;
	}
	else
	{
		pInfo->m_bContinuePrinting = FALSE;
	}
}


/*-----------------------------------------------------------------------------
[名称]	イベントハンドラ
[機能]	主にマウスイベント処理。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
void CShitarabianView::PrintColumn(
	CDC*			pDC,				//   O:出力先DC [マッピング:pixel] (-) :-
	CPrintInfo*		pInfo,				// I  :印刷情報 [-] (-) :-
	CSize			sizeMemDCPixel,		// I  :出力先DC大きさ [pixel] (-) :-
	int				iStartLine,			// I  :描画開始ドキュメント行 [-] (-) :-
	int				iEndLine			// I  :描画終了ドキュメント行 [-] (-) :-
)
{
	CEditDrawer*		pDrawer = CEditDrawer::GetInstance();
	CShitarabianDoc*	pDoc = GetDocument();
	CPrintDefine*		pPrint = CGeneralSetting::GetInstance()->GetPrintDefine();

	BOOL	bOnlySelection = pInfo->m_pPD->PrintSelection();

	// テキストの表示
	int		idxLine;
	for( idxLine=iStartLine ; idxLine<=iEndLine ; idxLine++ )
	{
		// ▼ (3192) BGN 2003.12.26 (dincom) 
		// 選択範囲のみ印刷のとき、選択範囲外に達したら印刷を終了する
		if ( bOnlySelection )
		if ( idxLine > pDoc->GetSelection()->GetSelectedEndRow() )
		{
			return;
		}
		// ▲ (3192) END

		int		iRow = idxLine - iStartLine;
		// 行を描画
		{
			CString*			pstr = pDoc->GetLine( idxLine );
			if ( pstr != NULL )
			{
				long boom = iRow * (pDrawer->CaretRowToPixel( 1 ) );
				CPoint	pt;
				pt.x = 0;
				pt.y = boom;

				// 選択範囲のみの設定の場合、選択テキスト範囲を反映する
				BOOL	bRgn1= FALSE, bRgn2 = FALSE;
				CRgn	rgn1, rgn2;
				if ( bOnlySelection )
				{
					// 選択開始行なら
					if ( idxLine == pDoc->GetSelection()->GetSelectedStartRow() )
					{
						// リージョンを制御する
						int		iStartPixelX = 0;
						CEmphasisLine*	pEmphasisLine = pDoc->GetEmphasisLine( idxLine );
						if ( pEmphasisLine != NULL )
						{
							iStartPixelX = pEmphasisLine->CaretColumnToPixel(
								pDoc->GetSelection()->GetSelectedStartColumn()
							);
						}

						rgn1.CreateRectRgn(
							iStartPixelX,
							pt.y,
							sizeMemDCPixel.cx,
							pt.y + pDrawer->CaretRowToPixel( 1 )
						);

						pDC->SelectClipRgn(
							&rgn1,
							RGN_AND
						);

						bRgn1 = TRUE;
					}

					// 終了行なら
					if ( idxLine == pDoc->GetSelection()->GetSelectedEndRow() )
					{
						// リージョンを制御する
						int		iEndPixelX = 0;
						CEmphasisLine*	pEmphasisLine = pDoc->GetEmphasisLine( idxLine );
						if ( pEmphasisLine != NULL )
						{
							iEndPixelX = pEmphasisLine->CaretColumnToPixel(
								pDoc->GetSelection()->GetSelectedEndColumn()
							);
						}

						rgn2.CreateRectRgn(
							0,
							pt.y,
							iEndPixelX,
							pt.y + pDrawer->CaretRowToPixel( 1 )
						);

						pDC->SelectClipRgn(
							&rgn2,
							RGN_AND
						);

						bRgn2 = TRUE;
					}
				}

				// 描画
				pDrawer->SetDstX( pt.x );
				pDrawer->SetDstY( pt.y );
				long	lXPixel;
				lXPixel = pDrawer->DrawPlaneLine(
						pDoc,
						pDC,
						idxLine,
						pPrint->m_bCareSelection
				);

				// リージョンの破棄
				if ( bRgn1 )
				{
					pDC->SelectClipRgn( NULL );
					rgn1.DeleteObject();
				}
				if ( bRgn2 )
				{
					pDC->SelectClipRgn( NULL );
					rgn2.DeleteObject();
				}
			}
		}
	}
}


/*-----------------------------------------------------------------------------
[名称]	ヘッダ描画
[機能]	ヘッダの描画。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
void CShitarabianView::PrintHeader(
	CDC*			pDC,				//   O:出力先DC [マッピング:pixel] (-) :-
	CPrintInfo*		pInfo,				// I  :印刷情報 [-] (-) :-
	CPrintDefine*	pPrint,				// I  :印刷定義 [-] (-) :-
	CSize			sizePrinterPageDP	// I  :印刷先DC大きさ [DP] (-) :-
)
{
	CSize	ptHeader;

	// フォントの設定
	CFont*	fontOld = (CFont*)(pDC->SelectObject( pPrint->m_fontHeader.GetFont( pDC ) ) );

	// 左肩座標計算 [プリンタDCのデバイス座標]
	ptHeader.cx = pPrint->m_lLeftMargin*100;
	ptHeader.cy = pPrint->m_lTopMargin*100;
	pDC->HIMETRICtoLP( &ptHeader );
	pDC->LPtoDP( &ptHeader );
	ptHeader.cx += pInfo->m_rectDraw.left;
	ptHeader.cy += pInfo->m_rectDraw.top;

	// 左端
	CString	strHeaderLeft = pPrint->Cooking( pPrint->m_strHeaderLeft, pInfo);
	if ( !strHeaderLeft.IsEmpty() )
	{
		CSize sizeHeaderLeft = pDC->GetTextExtent( strHeaderLeft );
		pDC->TextOut(
			ptHeader.cx,
			ptHeader.cy,
			strHeaderLeft
		);
	}

	// 中央
	CString	strHeaderMid = pPrint->Cooking( pPrint->m_strHeaderMid, pInfo);
	if ( !strHeaderMid.IsEmpty() )
	{
		CSize sizeHeaderMid = pDC->GetTextExtent( strHeaderMid );
		pDC->TextOut(
			ptHeader.cx + (sizePrinterPageDP.cx - sizeHeaderMid.cx )/2,
			ptHeader.cy,
			strHeaderMid
		);
	}

	// 右端
	CString	strHeaderRight = pPrint->Cooking( pPrint->m_strHeaderRight, pInfo);
	if ( !strHeaderRight.IsEmpty() )
	{
		CSize sizeHeaderRight = pDC->GetTextExtent( strHeaderRight );
		pDC->TextOut(
			ptHeader.cx + sizePrinterPageDP.cx - sizeHeaderRight.cx,
			ptHeader.cy,
			strHeaderRight
		);
	}
	pDC->SelectObject( fontOld );
}


/*-----------------------------------------------------------------------------
[名称]	フッダ描画
[機能]	フッダの描画。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
void CShitarabianView::PrintFooter(
	CDC*			pDC,				//   O:出力先DC [マッピング:pixel] (-) :-
	CPrintInfo*		pInfo,				// I  :印刷情報 [-] (-) :-
	CPrintDefine*	pPrint,				// I  :印刷定義 [-] (-) :-
	CSize			sizePrinterPageDP	// I  :印刷先DC大きさ [DP] (-) :-
)
{
	CSize				ptFooter;

	// フォントの設定
	CFont*	fontOld = (CFont*)(pDC->SelectObject( pPrint->m_fontFooter.GetFont( pDC ) ) );

	// 左肩座標計算 [プリンタDCのデバイス座標]
	ptFooter.cx = pPrint->m_lLeftMargin*100;
	ptFooter.cy = (pPrint->m_lBottomMargin)*100;
	pDC->HIMETRICtoLP( &ptFooter );
	pDC->LPtoDP( &ptFooter );
	ptFooter.cx += pInfo->m_rectDraw.left;
	ptFooter.cy = pInfo->m_rectDraw.bottom-ptFooter.cy;

	// 左端
	CString	strFooterLeft = pPrint->Cooking( pPrint->m_strFooterLeft, pInfo);
	if ( !strFooterLeft.IsEmpty() )
	{
		CSize sizeFooterLeft = pDC->GetTextExtent( strFooterLeft );
		pDC->TextOut(
			ptFooter.cx,
			ptFooter.cy - sizeFooterLeft.cy,
			strFooterLeft
		);
	}

	// 中央
	CString	strFooterMid = pPrint->Cooking( pPrint->m_strFooterMid, pInfo);
	if ( !strFooterMid.IsEmpty() )
	{
		CSize sizeFooterMid = pDC->GetTextExtent( strFooterMid );
		pDC->TextOut(
			ptFooter.cx + (sizePrinterPageDP.cx - sizeFooterMid.cx )/2,
			ptFooter.cy - sizeFooterMid.cy,
			strFooterMid
		);
	}

	// 右端
	CString	strFooterRight = pPrint->Cooking( pPrint->m_strFooterRight, pInfo);
	if ( !strFooterRight.IsEmpty() )
	{
		CSize sizeFooterRight = pDC->GetTextExtent( strFooterRight );
		pDC->TextOut(
			ptFooter.cx + sizePrinterPageDP.cx - sizeFooterRight.cx,
			ptFooter.cy - sizeFooterRight.cy,
			strFooterRight
		);
	}
	pDC->SelectObject( fontOld );
}
