/*******************************************************************************
  TPI - flexible but useless plug-in framework.
  Copyright (C) 2002-2009 Silky

  This library is free software; you can redistribute it and/or modify it under
  the terms of the GNU Lesser General Public License as published by the Free
  Software Foundation; either version 2.1 of the License, or (at your option)
  any later version.

  This library is distributed in the hope that it will be useful, but WITHOUT
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
  for more details.

  You should have received a copy of the GNU Lesser General Public License along
  with this library; if not, write to the Free Software Foundation, Inc.,
  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

  $Id: dlg_process.cpp 366 2010-10-01 12:50:31Z sirakaba $
*******************************************************************************/

#include "lychee.h"
#include "dlg_process.h"
#include "dlg_make.h"
#include "frm_main.h"
#include "functions.h"

ProcessDialog * g_procDlg = NULL;

//******************************************************************************
// ProcessDialog
//******************************************************************************

ProcessDialog::ProcessDialog(): wxDialog()
{
	::wxXmlResource::Get()->Load(L_DIR_S_XRC wxT("dlg_process.xrc"));
	::wxXmlResource::Get()->LoadDialog(this, this->GetParent(), wxT("dlg_process"));	
}

ProcessDialog::~ProcessDialog()
{
	g_procDlg = NULL;
}

//******************************************************************************
// Event table.
//******************************************************************************

BEGIN_EVENT_TABLE(ProcessDialog, wxDialog)
	EVT_INIT_DIALOG(ProcessDialog::OnInit)
	EVT_CLOSE(ProcessDialog::OnClose)
END_EVENT_TABLE()

//******************************************************************************
// Event handler.
//******************************************************************************

void ProcessDialog::OnInit(wxInitDialogEvent &)
{
	// XRCと結びつけ。
	this->ebTarget          = XRCCTRL(* this, "ebTarget",     wxTextCtrl);
	this->ebSource          = XRCCTRL(* this, "ebSource",     wxTextCtrl);
	this->gFile             = XRCCTRL(* this, "gFile",        wxGauge);
	this->gArchive          = XRCCTRL(* this, "gArchive",     wxGauge);
	this->fCancel           = false;
	this->nOverwriteMode    = wxID_OK;
	this->Update();
	g_procDlg = this;

	::wxXmlResource::Get()->Unload(L_DIR_S_XRC wxT("dlg_process.xrc"));
}

void ProcessDialog::OnClose(wxCloseEvent & e)
{
	if (e.CanVeto() && ::AskDlg(_("Really do you want to cancel this operation?"), this) == wxYES)
	{
		this->fCancel = true;
	}
	e.Veto();
}

int ProcessDialog::CallbackProc(unsigned int _uMsg, void * _pStructure)
{
	if (_uMsg != TPI_NOTIFY_COMMON)
	{
		return TPI_CALLBACK_UNSUPPORTED;
	}

	TPI_PROCESSINFO * piInfo = (TPI_PROCESSINFO *) _pStructure;
	if (piInfo == NULL || ! this->IsShown())
	{
		return TPI_CALLBACK_CONTINUE;
	}

	switch (piInfo->eMessage)
	{
	case TPI_MESSAGE_STATUS:
	{
		static int s_nGaugeCounter = 0, s_nInterval = 0;
		switch (piInfo->eStatus)
		{
		case TPI_STATUS_OPENARCHIVE:
			this->ebSource->ChangeValue(piInfo->fiInfo.fnFileName.GetFullPath());
			break;
		case TPI_STATUS_BEGINPROCESS:
			// 小さなファイルなら表示しない。
			if (piInfo->fiInfo.nUnpackedSize > 10000)
			{
				this->ebSource->ChangeValue(piInfo->fiInfo.fnFileName.GetFullPath());
				this->ebTarget->ChangeValue(piInfo->fnDestination.GetFullPath());
				this->gFile->SetRange(piInfo->fiInfo.nUnpackedSize);
				this->gFile->SetValue(0);
				::wxSafeYield(this, true);
			}
			break;
		case TPI_STATUS_INPROCESS:
			if (piInfo->fiInfo.nUnpackedSize > 10000)
			{
				this->gFile->SetValue(piInfo->nProcessedSize);
				::wxSafeYield(this, true);
			}
			break;
		case TPI_STATUS_ENDPROCESS:
			if (s_nGaugeCounter++ > s_nInterval)
			{
				this->gArchive->SetValue(this->gArchive->GetValue() + s_nInterval);
				::wxSafeYield(this, true);
				s_nGaugeCounter = 0;
			}
			break;
		// 書庫ロード時用の独自仕様。
		case 0x1000:
			this->ebSource->ChangeValue(piInfo->fiInfo.fnFileName.GetFullPath());
			this->gArchive->SetRange(piInfo->fiInfo.nUnpackedSize);
			this->gArchive->SetValue(0);
			this->Update();
			s_nInterval = piInfo->fiInfo.nUnpackedSize / 10;
			break;
		case 0x1001:
			if (piInfo->fiInfo.nUnpackedSize > 10000)
			{
				this->ebTarget->ChangeValue(piInfo->fiInfo.fnFileName.GetFullPath());
			}
			if (s_nGaugeCounter++ > s_nInterval)
			{
				this->gArchive->SetValue(piInfo->nProcessedSize);
				::wxSafeYield(this, true);
				s_nGaugeCounter = 0;
			}
			break;
		}
		break;
	}
	case TPI_MESSAGE_ASK:
	{
		switch (piInfo->eStatus)
		{
		case TPI_PARAM_PASSWORD:
		{
			static wxFileName fnFormer;
			static wxString szFormer;
			if (piInfo->fiInfo.fnFileName == fnFormer)
			{
				piInfo->szParam = ::wxGetPasswordFromUser(_("Password for:\n") + piInfo->fiInfo.fnFileName.GetFullPath(), wxT("Lychee"), wxEmptyString, this);
				if (piInfo->szParam.IsEmpty())
				{
					this->fCancel = true;
				}
				szFormer = piInfo->szParam;
			}
			else
			{
				piInfo->szParam = szFormer;
				fnFormer = piInfo->fiInfo.fnFileName;
			}
			break;
		}
		case TPI_PARAM_NEXTVOLUME:
		{
			wxFileDialog fd(this, _("Select next volume of: ") + piInfo->fiInfo.fnFileName.GetFullName());
			fd.SetWindowStyleFlag(wxFD_FILE_MUST_EXIST);
			if (fd.ShowModal() == wxID_CANCEL)
			{
				this->fCancel = true;
			}
			piInfo->szParam = fd.GetPath();
			break;
		}
		case TPI_PARAM_DEST:
			if (piInfo->fnDestination.FileExists() || ::wxDirExists(piInfo->fnDestination.GetFullPath()))
			{
				// 上書き確認を行う。
				bool bPerm = false;
				if (this->nOverwriteMode == wxID_OK)
				{
					OverwriteDialog odDlg;
					odDlg.fnExist = & piInfo->fnDestination;
					odDlg.tmWrite = & piInfo->fiInfo.tmModified;
					odDlg.nWriteSize = piInfo->fiInfo.nUnpackedSize;

					this->nOverwriteMode = odDlg.ShowModal();
					bPerm = odDlg.cbApplyAll->IsChecked();
				}
				else
				{
					bPerm = true;
				}
				switch (this->nOverwriteMode)
				{
				case wxID_CANCEL:
					this->fCancel = true;
					break;
				case 0:
					// 自動上書き。既存のファイルを削除しておく。
					if (piInfo->fnDestination.FileExists())
					{
						::wxRemoveFile(piInfo->fnDestination.GetFullPath());
					}
					else if (::wxDirExists(piInfo->fnDestination.GetFullPath()))
					{
						// TODO: 再帰削除。
						::wxRmdir(piInfo->fnDestination.GetFullPath());
					}
					break;
				case 1:
					// 自動スキップ。
					piInfo->fnDestination.Clear();
					break;
				case 2:
					// 自動リネーム。
					break;
				}
				if (! bPerm)
				{
					this->nOverwriteMode = wxID_OK;
				}
			}
			break;
		default:
			return TPI_CALLBACK_UNSUPPORTED;
		}
		break;
	}
	default:
		return TPI_CALLBACK_UNSUPPORTED;
	}

	return this->fCancel ? TPI_CALLBACK_CANCEL : TPI_CALLBACK_CONTINUE;
}
//******************************************************************************
// OverwriteDialog
//******************************************************************************

OverwriteDialog::OverwriteDialog(): wxDialog()
{
	::wxXmlResource::Get()->Load(L_DIR_S_XRC wxT("dlg_overwrite.xrc"));
	::wxXmlResource::Get()->LoadDialog(this, this->GetParent(), wxT("dlg_overwrite"));	
}

//******************************************************************************
// Event table.
//******************************************************************************

BEGIN_EVENT_TABLE(OverwriteDialog, wxDialog)
	EVT_INIT_DIALOG(OverwriteDialog::OnInit)
	EVT_BUTTON(XRCID("btnOverwrite"), OverwriteDialog::OnBtnOverwrite)
	EVT_BUTTON(XRCID("btnSkip"), OverwriteDialog::OnBtnSkip)
	EVT_BUTTON(XRCID("btnAuto"), OverwriteDialog::OnBtnAuto)
	EVT_BUTTON(XRCID("btnBrowse"), OverwriteDialog::OnBtnBrowse)
	EVT_CLOSE(OverwriteDialog::OnClose)
END_EVENT_TABLE()

//******************************************************************************
// Event handler.
//******************************************************************************

void OverwriteDialog::OnInit(wxInitDialogEvent &)
{
	// XRCと結びつけ。
	this->ebTarget          = XRCCTRL(* this, "ebTarget",     wxTextCtrl);
	this->cbApplyAll        = XRCCTRL(* this, "cbApplyAll",   wxCheckBox);
	::wxXmlResource::Get()->Unload(L_DIR_S_XRC wxT("dlg_overwrite.xrc"));

	// ファイル情報を設定。
	this->ebTarget->SetValue(this->fnExist->GetFullPath());
	XRCCTRL(* this, "stExistTime", wxStaticText)->SetLabel(this->fnExist->GetModificationTime().Format(_("%Y/%m/%d %H:%M:%S modified, ")));
	XRCCTRL(* this, "stExistSize", wxStaticText)->SetLabel(this->fnExist->GetHumanReadableSize());
	XRCCTRL(* this, "stWriteTime", wxStaticText)->SetLabel(this->tmWrite->Format(_("%Y/%m/%d %H:%M:%S modified, ")));
	XRCCTRL(* this, "stWriteSize", wxStaticText)->SetLabel(wxFileName::GetHumanReadableSize((wxULongLong) this->nWriteSize));
	XRCCTRL(* this, "sbIcon", wxStaticBitmap)->SetIcon(GetFileTypeIcon(* this->fnExist));
}

void OverwriteDialog::OnClose(wxCloseEvent & e)
{
	if (e.CanVeto() && ::AskDlg(_("Really do you want to cancel this operation?"), this) == wxYES)
	{
		this->EndModal(wxID_CANCEL);
	}
	e.Veto();
}

void OverwriteDialog::OnBtnOverwrite(wxCommandEvent&)
{
	if (this->fnExist->GetFullPath() != this->ebTarget->GetValue())
	{
		// 保存先を変えているので、次回もダイアログを表示。
		this->cbApplyAll->SetValue(false);
		* this->fnExist = wxFileName(this->ebTarget->GetValue());
	}
	this->EndModal(0);
}

void OverwriteDialog::OnBtnSkip(wxCommandEvent&)
{
	this->EndModal(1);
}

void OverwriteDialog::OnBtnAuto(wxCommandEvent&)
{
	this->EndModal(2);
}

void OverwriteDialog::OnBtnBrowse(wxCommandEvent&)
{
	wxFileDialog fd(this);
	fd.SetWindowStyleFlag(wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
	fd.SetPath(this->ebTarget->GetValue());
	if (fd.ShowModal() == wxID_OK)
	{
		this->ebTarget->SetValue(fd.GetPath());
	}
}

//******************************************************************************
//    ダイアログプロシージャ
//******************************************************************************

int __stdcall TPICallbackProc(unsigned int _uMsg, void * _pStructure)
{
	return g_procDlg == NULL ? TPI_CALLBACK_CONTINUE : g_procDlg->CallbackProc(_uMsg, _pStructure);
}
