// Berkeley Open Infrastructure for Network Computing
// http://boinc.berkeley.edu
// Copyright (C) 2005 University of California
//
// This 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 software 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.
//
// To view the GNU Lesser General Public License visit
// http://www.gnu.org/copyleft/lesser.html
// or write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#if defined(__GNUG__) && !defined(__APPLE__)
#pragma implementation "sg_DlgMessages.h"
#endif

#include "stdwx.h"
#include "common_defs.h"
#include "diagnostics.h"
#include "str_util.h"
#include "mfile.h"
#include "miofile.h"
#include "parse.h"
#include "error_numbers.h"
#include "Events.h"
#include "BOINCGUIApp.h"
#include "SkinManager.h"
#include "MainDocument.h"
#include "hyperlink.h"
#include "sg_DlgMessages.h"
#include "sg_SGUIListControl.h"

// BUGBUG: Don't have a clue why the build env is acting wierd
#ifdef  __WXGTK__
#ifndef __WXGTK20__
#undef  wxUSE_CLIPBOARD
#endif
#endif

////@begin includes
////@end includes

////@begin XPM images
////@end XPM images


#define COLUMN_PROJECT              0
#define COLUMN_TIME                 1
#define COLUMN_MESSAGE              2

/*!
 * CPanelPreferences type definition
 */

IMPLEMENT_DYNAMIC_CLASS( CPanelMessages, wxPanel )

/*!
 * CPanelPreferences event table definition
 */

BEGIN_EVENT_TABLE( CPanelMessages, wxPanel )
////@begin CPanelPreferences event table entries
    EVT_ERASE_BACKGROUND( CPanelMessages::OnEraseBackground )
    EVT_TIMER(ID_REFRESHMESSAGESTIMER, CPanelMessages::OnRefresh)
    EVT_BUTTON( wxID_OK, CPanelMessages::OnOK )
    EVT_BUTTON(ID_COPYAll, CPanelMessages::OnMessagesCopyAll)
    EVT_BUTTON(ID_COPYSELECTED, CPanelMessages::OnMessagesCopySelected)
    EVT_BUTTON(ID_SIMPLE_HELP, CPanelMessages::OnButtonHelp)
////@end CPanelPreferences event table entries
END_EVENT_TABLE()

/*!
 * CPanelMessages constructors
 */

CPanelMessages::CPanelMessages( )
{
}


CPanelMessages::CPanelMessages( wxWindow* parent ) :  
    wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNO_BORDER)
{
    Create();
}


/*!
 * CPanelMessages creator
 */

bool CPanelMessages::Create()
{
////@begin CPanelMessages member initialisation
    m_iPreviousDocCount = 0;
	m_bProcessingRefreshEvent = false;
////@end CPanelMessages member initialisation

    CreateControls();

    GetSizer()->Fit(this);
    GetSizer()->SetSizeHints(this);

	// Create List Pane Items
    m_pList->InsertColumn(COLUMN_PROJECT, _("Project"), wxLIST_FORMAT_LEFT, 109);
    m_pList->InsertColumn(COLUMN_TIME, _("Time"), wxLIST_FORMAT_LEFT, 130);
    m_pList->InsertColumn(COLUMN_MESSAGE, _("Message"), wxLIST_FORMAT_LEFT, 378);

	m_pMessageInfoAttr = new wxListItemAttr(*wxBLACK, *wxWHITE, wxNullFont);
    m_pMessageErrorAttr = new wxListItemAttr(*wxRED, *wxWHITE, wxNullFont);

	m_pRefreshMessagesTimer = new wxTimer(this, ID_REFRESHMESSAGESTIMER);
    wxASSERT(m_pRefreshMessagesTimer);

    m_pRefreshMessagesTimer->Start(1000);  

    return true;
}


CPanelMessages::~CPanelMessages()
{
	if (m_pRefreshMessagesTimer) {
        m_pRefreshMessagesTimer->Stop();
        delete m_pRefreshMessagesTimer;
    }
	if (m_pMessageInfoAttr) {
        delete m_pMessageInfoAttr;
        m_pMessageInfoAttr = NULL;
    }

    if (m_pMessageErrorAttr) {
        delete m_pMessageErrorAttr;
        m_pMessageErrorAttr = NULL;
    }

}


/*!
 * Control creation for CPanelPreferences
 */

void CPanelMessages::CreateControls()
{
    CPanelMessages* itemDialog1 = this;
    CSkinSimple* pSkinSimple = wxGetApp().GetSkinManager()->GetSimple();

    wxASSERT(pSkinSimple);
    wxASSERT(wxDynamicCast(pSkinSimple, CSkinSimple));

    wxFlexGridSizer* itemFlexGridSizer2 = new wxFlexGridSizer(2, 1, 0, 0);
    itemFlexGridSizer2->AddGrowableRow(0);
    itemFlexGridSizer2->AddGrowableCol(0);
    itemDialog1->SetSizer(itemFlexGridSizer2);

    m_pList = new CSGUIListCtrl(this, ID_SIMPLE_MESSAGESVIEW, DEFAULT_LIST_MULTI_SEL_FLAGS);
    itemFlexGridSizer2->Add(m_pList, 0, wxGROW|wxALL, 5);

    wxBoxSizer* itemBoxSizer4 = new wxBoxSizer(wxHORIZONTAL);
    
#ifdef __WXMAC__            // Don't let Close button overlap window's grow icon
    itemFlexGridSizer2->Add(itemBoxSizer4, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL|wxALL, 12);
#else
    itemFlexGridSizer2->Add(itemBoxSizer4, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL|wxALL, 5);
#endif

#ifdef wxUSE_CLIPBOARD
    wxBitmapButton* itemButton1 = new wxBitmapButton(
        this,
        ID_COPYAll,
        *pSkinSimple->GetCopyAllButton()->GetBitmap(),
        wxDefaultPosition,
        wxSize(
            (*pSkinSimple->GetCopyAllButton()->GetBitmap()).GetWidth(),
            (*pSkinSimple->GetCopyAllButton()->GetBitmap()).GetHeight()
        ),
        wxBU_AUTODRAW
    );
	if ( pSkinSimple->GetCopyAllButton()->GetBitmapClicked() != NULL ) {
		itemButton1->SetBitmapSelected(*pSkinSimple->GetCopyAllButton()->GetBitmapClicked());
	}
    itemButton1->SetHelpText(
        _("Copy all the messages to the clipboard.")
    );
#if wxUSE_TOOLTIPS
    itemButton1->SetToolTip(
        _("Copy all the messages to the clipboard.")
    );
#endif
    itemBoxSizer4->Add(itemButton1, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);

    wxBitmapButton* itemButton2 = new wxBitmapButton(
        this,
        ID_COPYSELECTED,
        *pSkinSimple->GetCopyButton()->GetBitmap(),
        wxDefaultPosition,
        wxSize(
            (*pSkinSimple->GetCopyButton()->GetBitmap()).GetWidth(),
            (*pSkinSimple->GetCopyButton()->GetBitmap()).GetHeight()
        ),
        wxBU_AUTODRAW
    );
	if ( pSkinSimple->GetCopyButton()->GetBitmapClicked() != NULL ) {
		itemButton2->SetBitmapSelected(*pSkinSimple->GetCopyButton()->GetBitmapClicked());
	}
    itemButton2->SetHelpText(
#ifdef __WXMAC__
        _("Copy the selected messages to the clipboard. "
          "You can select multiple messages by holding down the shift "
          "or command key while clicking on messages.")
#else
        _("Copy the selected messages to the clipboard. "
          "You can select multiple messages by holding down the shift "
          "or control key while clicking on messages.")
#endif
    );
#if wxUSE_TOOLTIPS
    itemButton2->SetToolTip(
#ifdef __WXMAC__
        _("Copy the selected messages to the clipboard. "
          "You can select multiple messages by holding down the shift "
          "or command key while clicking on messages.")
#else
        _("Copy the selected messages to the clipboard. "
          "You can select multiple messages by holding down the shift "
          "or control key while clicking on messages.")
#endif
    );
#endif
    itemBoxSizer4->Add(itemButton2, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
#endif

    wxBitmapButton* itemBitmapButton44 = new wxBitmapButton(
        this,
        wxID_OK,
        *pSkinSimple->GetCloseButton()->GetBitmap(),
        wxDefaultPosition,
        wxSize(
            (*pSkinSimple->GetCloseButton()->GetBitmap()).GetWidth(),
            (*pSkinSimple->GetCloseButton()->GetBitmap()).GetHeight()
        ),
        wxBU_AUTODRAW
    );
	if ( pSkinSimple->GetCloseButton()->GetBitmapClicked() != NULL ) {
		itemBitmapButton44->SetBitmapSelected(*pSkinSimple->GetCloseButton()->GetBitmapClicked());
	}
    itemBoxSizer4->Add(itemBitmapButton44, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);

#ifndef __WXMSW__
#ifdef __WXMAC__
	wxBitmapButton* itemButton45 = new wxBitmapButton(
        this,
        ID_SIMPLE_HELP,
        *pSkinSimple->GetHelpButton()->GetBitmap(),
        wxDefaultPosition,
        wxSize(
            (*pSkinSimple->GetHelpButton()->GetBitmap()).GetWidth(),
            (*pSkinSimple->GetHelpButton()->GetBitmap()).GetHeight()
        ),
        wxBU_AUTODRAW
    );
	if ( pSkinSimple->GetHelpButton()->GetBitmapClicked() != NULL ) {
		itemButton45->SetBitmapSelected(*pSkinSimple->GetHelpButton()->GetBitmapClicked());
	}
#ifdef wxUSE_TOOLTIPS
	itemButton45->SetToolTip(new wxToolTip(_("Get help with BOINC")));
#endif
    itemBoxSizer4->Add(itemButton45, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
#else
    wxContextHelpButton* itemButton45 = new wxContextHelpButton(this);
    itemBoxSizer4->Add(itemButton45, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
#endif
#endif

}


/*!
 * wxEVT_ERASE_BACKGROUND event handler for ID_DLGMESSAGES
 */

void CPanelMessages::OnEraseBackground(wxEraseEvent& event){
    CSkinSimple* pSkinSimple = wxGetApp().GetSkinManager()->GetSimple();
    
    wxASSERT(pSkinSimple);
    wxASSERT(wxDynamicCast(pSkinSimple, CSkinSimple));

    wxMemoryDC memDC;
    wxCoord w, h, x, y;

    // Get the desired background bitmap
    wxBitmap bmp(*pSkinSimple->GetDialogBackgroundImage()->GetBitmap());

    // Dialog dimensions
    wxSize sz = GetClientSize();

    // Create a buffered device context to reduce flicker
    wxBufferedDC dc(event.GetDC(), sz, wxBUFFER_CLIENT_AREA);

    // bitmap dimensions
    w = bmp.GetWidth();
    h = bmp.GetHeight();

    // Fill the dialog with a magenta color so people can detect when something
    //   is wrong
    dc.SetBrush(wxBrush(wxColour(255,0,255)));
    dc.SetPen(wxPen(wxColour(255,0,255)));
    dc.DrawRectangle(0, 0, sz.GetWidth(), sz.GetHeight());

    // Is the bitmap smaller than the window?
    if ( (w < sz.x) || (h < sz.y) ) {
        // Check to see if they need to be rescaled to fit in the window
        wxImage img = bmp.ConvertToImage();
        img.Rescale((int) sz.x, (int) sz.y);

        // Draw our cool background (centered)
        dc.DrawBitmap(wxBitmap(img), 0, 0);
    } else {
        // Snag the center of the bitmap and use it
        //   for the background image
        x = wxMax(0, (w - sz.x)/2);
        y = wxMax(0, (h - sz.y)/2);

        // Select the desired bitmap into the memory DC so we can take
        //   the center chunk of it.
        memDC.SelectObject(bmp);

        // Draw the center chunk on the window
        dc.Blit(0, 0, w, h, &memDC, x, y, wxCOPY);

        // Drop the bitmap
        memDC.SelectObject(wxNullBitmap);
    }
}


/*!
 * wxEVT_TIMER event handler for ID_REFRESHMESSAGESTIMER
 */

void CPanelMessages::OnRefresh(wxTimerEvent& event) {
    if (!m_bProcessingRefreshEvent) {
        m_bProcessingRefreshEvent = true;

        wxASSERT(m_pList);

        wxInt32 iDocCount = wxGetApp().GetDocument()->GetMessageCount();
        if (0 >= iDocCount) {
            m_pList->DeleteAllItems();
        } else {
            if (m_iPreviousDocCount != iDocCount)
                m_pList->SetItemCount(iDocCount);
        }

        if ((iDocCount) && (EnsureLastItemVisible()) && (m_iPreviousDocCount != iDocCount)) {
            m_pList->EnsureVisible(iDocCount - 1);
        }

        if (m_iPreviousDocCount != iDocCount) {
            m_iPreviousDocCount = iDocCount;
        }

        m_bProcessingRefreshEvent = false;
    }

    event.Skip();
}


/*!
 * wxEVT_COMMAND_BUTTON_CLICKED event handler for wxID_OK
 */

void CPanelMessages::OnOK( wxCommandEvent& event ) {
    event.Skip();
}


/*!
 * wxEVT_COMMAND_BUTTON_CLICKED event handler for ID_COPYAll
 */

void CPanelMessages::OnMessagesCopyAll( wxCommandEvent& WXUNUSED(event) ) {
    wxLogTrace(wxT("Function Start/End"), wxT("CPanelMessages::OnMessagesCopyAll - Function Begin"));

#ifdef wxUSE_CLIPBOARD
    wxInt32 iIndex          = -1;
    wxInt32 iRowCount       = 0;
    OpenClipboard();

    iRowCount = m_pList->GetItemCount();
    for (iIndex = 0; iIndex < iRowCount; iIndex++) {
        CopyToClipboard(iIndex);            
    }

    CloseClipboard();
#endif

    wxLogTrace(wxT("Function Start/End"), wxT("CPanelMessages::OnMessagesCopyAll - Function End"));
}


/*!
 * wxEVT_COMMAND_BUTTON_CLICKED event handler for ID_COPYSELECTED
 */

void CPanelMessages::OnMessagesCopySelected( wxCommandEvent& WXUNUSED(event) ) {
    wxLogTrace(wxT("Function Start/End"), wxT("CPanelMessages::OnMessagesCopySelected - Function Begin"));

#ifdef wxUSE_CLIPBOARD
    wxInt32 iIndex = -1;

    OpenClipboard();

    for (;;) {
        iIndex = m_pList->GetNextItem(
            iIndex, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED
        );
        if (iIndex == -1) break;

        CopyToClipboard(iIndex);            
    }

    CloseClipboard();
#endif

    wxLogTrace(wxT("Function Start/End"), wxT("CPanelMessages::OnMessagesCopySelected - Function End"));
}


/*!
 * wxEVT_COMMAND_BUTTON_CLICKED event handler for ID_SIMPLE_HELP
 */

void CPanelMessages::OnButtonHelp( wxCommandEvent& WXUNUSED(event) ) {
    wxLogTrace(wxT("Function Start/End"), wxT("CPanelMessages::OnHelp - Function Begin"));

	std::string url;
	url = wxGetApp().GetSkinManager()->GetAdvanced()->GetCompanyWebsite().mb_str();
	canonicalize_master_url(url);

	wxString wxurl;
	wxurl.Printf(wxT("%smanager_links.php?target=simple"), url.c_str());
    wxHyperLink::ExecuteLink(wxurl);

    wxLogTrace(wxT("Function Start/End"), wxT("CPanelMessages::OnHelp - Function End"));
}


bool CPanelMessages::OnSaveState(wxConfigBase* pConfig) {
    wxString    strBaseConfigLocation = wxEmptyString;
    wxListItem  liColumnInfo;
    wxInt32     iIndex = 0;
    wxInt32     iColumnCount = 0;


    wxASSERT(pConfig);


    // Retrieve the base location to store configuration information
    // Should be in the following form: "/Projects/"
    strBaseConfigLocation = pConfig->GetPath() + wxT("/");

    // Convert to a zero based index
    iColumnCount = m_pList->GetColumnCount() - 1;

    // Which fields are we interested in?
    liColumnInfo.SetMask(
        wxLIST_MASK_TEXT |
        wxLIST_MASK_WIDTH |
        wxLIST_MASK_FORMAT
    );

    // Cycle through the columns recording anything interesting
    for (iIndex = 0; iIndex <= iColumnCount; iIndex++) {
        m_pList->GetColumn(iIndex, liColumnInfo);

        pConfig->SetPath(strBaseConfigLocation + liColumnInfo.GetText());

        pConfig->Write(wxT("Width"), liColumnInfo.GetWidth());
        
#if (defined(__WXMAC__) &&  wxCHECK_VERSION(2,8,0))
        pConfig->Write(wxT("Width"), m_pList->GetColumnWidth(iIndex)); // Work around bug in wxMac-2.8.0 wxListCtrl::SetColumn()
#endif
    }


    return true;
}


bool CPanelMessages::OnRestoreState(wxConfigBase* pConfig) {
    wxString    strBaseConfigLocation = wxEmptyString;
    wxListItem  liColumnInfo;
    wxInt32     iIndex = 0;
    wxInt32     iColumnCount = 0;
    wxInt32     iTempValue = 0;


    wxASSERT(pConfig);


    // Retrieve the base location to store configuration information
    // Should be in the following form: "/Projects/"
    strBaseConfigLocation = pConfig->GetPath() + wxT("/");

    // Convert to a zero based index
    iColumnCount = m_pList->GetColumnCount() - 1;

    // Which fields are we interested in?
    liColumnInfo.SetMask(
        wxLIST_MASK_TEXT |
        wxLIST_MASK_WIDTH |
        wxLIST_MASK_FORMAT
    );

    // Cycle through the columns recording anything interesting
    for (iIndex = 0; iIndex <= iColumnCount; iIndex++) {
        m_pList->GetColumn(iIndex, liColumnInfo);

        pConfig->SetPath(strBaseConfigLocation + liColumnInfo.GetText());

        pConfig->Read(wxT("Width"), &iTempValue, -1);
        if (-1 != iTempValue) {
            liColumnInfo.SetWidth(iTempValue);
#if (defined(__WXMAC__) &&  wxCHECK_VERSION(2,8,0))
            m_pList->SetColumnWidth(iIndex,iTempValue); // Work around bug in wxMac-2.8.0 wxListCtrl::SetColumn()
#endif
        }

        m_pList->SetColumn(iIndex, liColumnInfo);
    }

    return true;
}


wxString CPanelMessages::OnListGetItemText(long item, long column) const {
    wxString        strBuffer   = wxEmptyString;

    switch(column) {
    case COLUMN_PROJECT:
        FormatProjectName(item, strBuffer);
        break;
    case COLUMN_TIME:
        FormatTime(item, strBuffer);
        break;
    case COLUMN_MESSAGE:
        FormatMessage(item, strBuffer);
        break;
    }

    return strBuffer;
}


wxListItemAttr* CPanelMessages::OnListGetItemAttr(long item) const {
    wxListItemAttr* pAttribute  = NULL;
    wxString        strBuffer   = wxEmptyString;

	FormatPriority(item, strBuffer);

    if (wxT("E") == strBuffer) {
        pAttribute = m_pMessageErrorAttr;
    } else {
        pAttribute = m_pMessageInfoAttr;
    }

    return pAttribute;
	
}


bool CPanelMessages::EnsureLastItemVisible() {
    return true;
}


wxInt32 CPanelMessages::FormatProjectName(wxInt32 item, wxString& strBuffer) const {
    MESSAGE* message = wxGetApp().GetDocument()->message(item);

    if (message) {
        strBuffer = wxString(message->project.c_str(), wxConvUTF8);
    }

    return 0;
}


wxInt32 CPanelMessages::FormatPriority(wxInt32 item, wxString& strBuffer) const {
    MESSAGE* message = wxGetApp().GetDocument()->message(item);

    if (message) {
        switch(message->priority) {
        case MSG_INFO:
            strBuffer = wxT("I");
            break;
        default:
            strBuffer = wxT("E");
            break;
        }
    }

    return 0;
}


wxInt32 CPanelMessages::FormatTime(wxInt32 item, wxString& strBuffer) const {
    wxDateTime dtBuffer;
    MESSAGE*   message = wxGetApp().GetDocument()->message(item);

    if (message) {
        dtBuffer.Set((time_t)message->timestamp);
        strBuffer = dtBuffer.Format();
    }

    return 0;
}


wxInt32 CPanelMessages::FormatMessage(wxInt32 item, wxString& strBuffer) const {
    MESSAGE*   message = wxGetApp().GetDocument()->message(item);

    if (message) {
        strBuffer = wxString(message->body.c_str(), wxConvUTF8);
    }

    strBuffer.Replace(wxT("\n"), wxT(""), true);

    return 0;
}


#ifdef wxUSE_CLIPBOARD
bool CPanelMessages::OpenClipboard() {
    bool bRetVal = false;

    bRetVal = wxTheClipboard->Open();
    if (bRetVal) {
        m_bClipboardOpen = true;
        m_strClipboardData = wxEmptyString;
        wxTheClipboard->Clear();
    }

    return bRetVal;
}


wxInt32 CPanelMessages::CopyToClipboard(wxInt32 item) {
    wxInt32        iRetVal = -1;

    if (m_bClipboardOpen) {
        wxString       strBuffer = wxEmptyString;
        wxString       strTimeStamp = wxEmptyString;
        wxString       strProject = wxEmptyString;
        wxString       strMessage = wxEmptyString;

        FormatTime(item, strTimeStamp);
        FormatProjectName(item, strProject);
        FormatMessage(item, strMessage);

#ifdef __WXMSW__
        strBuffer.Printf(wxT("%s|%s|%s\r\n"), strTimeStamp.c_str(), strProject.c_str(), strMessage.c_str());
#else
        strBuffer.Printf(wxT("%s|%s|%s\n"), strTimeStamp.c_str(), strProject.c_str(), strMessage.c_str());
#endif

        m_strClipboardData += strBuffer;

        iRetVal = 0;
    }

    return iRetVal;
}


bool CPanelMessages::CloseClipboard() {
    bool bRetVal = false;

    if (m_bClipboardOpen) {
        wxTheClipboard->SetData(new wxTextDataObject(m_strClipboardData));
        wxTheClipboard->Close();

        m_bClipboardOpen = false;
        m_strClipboardData = wxEmptyString;
    }

    return bRetVal;
}

#endif


/*!
 * CDlgMessages type definition
 */

IMPLEMENT_DYNAMIC_CLASS( CDlgMessages, wxDialog )

/*!
 * CDlgMessages event table definition
 */

BEGIN_EVENT_TABLE( CDlgMessages, wxDialog )
////@begin CDlgMessages event table entries
    EVT_HELP(wxID_ANY, CDlgMessages::OnHelp)
    EVT_SHOW( CDlgMessages::OnShow )
    EVT_BUTTON( wxID_OK, CDlgMessages::OnOK )
////@end CDlgMessages event table entries
END_EVENT_TABLE()

/*!
 * CDlgMessages constructors
 */

CDlgMessages::CDlgMessages( )
{
}


CDlgMessages::CDlgMessages( wxWindow* parent, wxWindowID id, const wxString& caption, const wxPoint& pos, const wxSize& size, long style )
{
    Create(parent, id, caption, pos, size, style);
}


CDlgMessages::~CDlgMessages() {
    wxLogTrace(wxT("Function Start/End"), wxT("CDlgMessages::CDlgMessages - Destructor Function Begin"));

	SaveState();    // Save state if close box on window frame clicked

    wxLogTrace(wxT("Function Start/End"), wxT("CDlgMessages::CDlgMessages - Destructor Function End"));
}


/*!
 * CDlgMessages creator
 */

bool CDlgMessages::Create( wxWindow* parent, wxWindowID id, const wxString& caption, const wxPoint& pos, const wxSize& size, long style )
{
    wxString strCaption = caption;
    if (strCaption.IsEmpty()) {
        CSkinAdvanced*         pSkinAdvanced = wxGetApp().GetSkinManager()->GetAdvanced();
        wxASSERT(pSkinAdvanced);
        wxASSERT(wxDynamicCast(pSkinAdvanced, CSkinAdvanced));

        strCaption.Printf(_("%s - Messages"), pSkinAdvanced->GetApplicationName().c_str());
    }

    SetExtraStyle(GetExtraStyle()|wxDIALOG_EX_CONTEXTHELP|wxWS_EX_BLOCK_EVENTS);

    wxDialog::Create( parent, id, strCaption, pos, size, style );

    SetBackgroundStyle(wxBG_STYLE_CUSTOM);

    Freeze();

#ifdef __WXDEBUG__
    SetBackgroundColour(wxColour(255, 0, 255));
#endif
    SetForegroundColour(*wxBLACK);

    CreateControls();

    GetSizer()->Fit(this);
    GetSizer()->SetSizeHints(this);
    Center();

    // To work properly on Mac, RestoreState() must be called _after_ 
    //  calling GetSizer()->Fit(), GetSizer()->SetSizeHints() and Center()
    RestoreState();   

    Thaw();

    return true;
}


/*!
 * Control creation for CDlgMessages
 */

void CDlgMessages::CreateControls(){
    wxFlexGridSizer* itemFlexGridSizer2 = new wxFlexGridSizer(1, 1, 0, 0);
    itemFlexGridSizer2->AddGrowableRow(0);
    itemFlexGridSizer2->AddGrowableCol(0);
    SetSizer(itemFlexGridSizer2);

    m_pBackgroundPanel = new CPanelMessages(this);
    itemFlexGridSizer2->Add(m_pBackgroundPanel, 0, wxGROW, 0);

    SetSizer(itemFlexGridSizer2);
}


/*!
 * wxEVT_SHOW event handler for ID_DLGMESSAGES
 */

void CDlgMessages::OnShow(wxShowEvent& event) {
    wxLogTrace(wxT("Function Start/End"), wxT("CDlgMessages::OnShow - Function Begin"));
    static bool bAlreadyRunning = false;

    if ((event.GetEventObject() == this) && !bAlreadyRunning) {
        bAlreadyRunning = true;

        wxLogTrace(wxT("Function Status"), wxT("CDlgMessages::OnShow - Show/Hide Event for CAdvancedFrame detected"));
        if (event.GetShow()) {
            RestoreWindowDimensions();
        } else {
            SaveWindowDimensions();
        }

        bAlreadyRunning = false;
    } else {
        event.Skip();
    }

    wxLogTrace(wxT("Function Start/End"), wxT("CDlgMessages::OnShow - Function End"));
}


/*!
 * wxEVT_HELP event handler for ID_DLGMESSAGES
 */

void CDlgMessages::OnHelp(wxHelpEvent& event) {
    wxLogTrace(wxT("Function Start/End"), wxT("CDlgMessages::OnHelp - Function Begin"));

    if (IsShown()) {
		std::string url;
		url = wxGetApp().GetSkinManager()->GetAdvanced()->GetCompanyWebsite().mb_str();
		canonicalize_master_url(url);

		wxString wxurl;
		wxurl.Printf(wxT("%smanager_links.php?target=simple_messages&controlid=%d"), url.c_str(), event.GetId());
        wxHyperLink::ExecuteLink(wxurl);
    }

    wxLogTrace(wxT("Function Start/End"), wxT("CDlgMessages::OnHelp - Function End"));
}


/*!
 * wxEVT_COMMAND_BUTTON_CLICKED event handler for wxID_OK
 */

void CDlgMessages::OnOK( wxCommandEvent& /*event*/ ) {
    SaveState();
    EndModal(wxID_OK);
}


bool CDlgMessages::SaveState() {
    wxLogTrace(wxT("Function Start/End"), wxT("CDlgMessages::SaveState - Function Begin"));

    wxString        strBaseConfigLocation = wxString(wxT("/Simple/Messages"));
    wxConfigBase*   pConfig = wxConfigBase::Get(FALSE);

    wxASSERT(pConfig);

    // An odd case happens every once and awhile where wxWidgets looses
    //   the pointer to the config object, or it is cleaned up before
    //   the window has finished it's cleanup duty.  If we detect a NULL
    //   pointer, return false.
    if (!pConfig) return false;

    //
    // Save Frame State
    //
    pConfig->SetPath(strBaseConfigLocation);

    // Reterieve and store the latest window dimensions.
    SaveWindowDimensions();

    // Save the list ctrl state
    m_pBackgroundPanel->OnSaveState(pConfig);

    wxLogTrace(wxT("Function Start/End"), wxT("CDlgMessages::SaveState - Function End"));
    return true;
}


void CDlgMessages::SaveWindowDimensions() {
    wxString        strBaseConfigLocation = wxString(wxT("/Simple/Messages"));
    wxConfigBase*   pConfig = wxConfigBase::Get(FALSE);

    wxASSERT(pConfig);

    pConfig->SetPath(strBaseConfigLocation);

    pConfig->Write(wxT("WindowIconized"), IsIconized());
    pConfig->Write(wxT("WindowMaximized"), IsMaximized());
    pConfig->Write(wxT("Width"), GetSize().GetWidth());
    pConfig->Write(wxT("Height"), GetSize().GetHeight());

#ifdef __WXMAC__
    pConfig->Write(wxT("XPos"), GetPosition().x);
    pConfig->Write(wxT("YPos"), GetPosition().y);
#endif  // ! __WXMAC__
}
    

bool CDlgMessages::RestoreState() {
    wxLogTrace(wxT("Function Start/End"), wxT("CDlgMessages::RestoreState - Function Begin"));

    wxString        strBaseConfigLocation = wxString(wxT("/Simple/Messages"));
    wxConfigBase*   pConfig = wxConfigBase::Get(FALSE);

    wxASSERT(pConfig);

    // An odd case happens every once and awhile where wxWidgets looses
    //   the pointer to the config object, or it is cleaned up before
    //   the window has finished it's cleanup duty.  If we detect a NULL
    //   pointer, return false.
    if (!pConfig) return false;

    //
    // Restore Frame State
    //
    pConfig->SetPath(strBaseConfigLocation);

    // Restore the windows properties
    RestoreWindowDimensions();

    // Restore the list ctrl state
    m_pBackgroundPanel->OnRestoreState(pConfig);

    wxLogTrace(wxT("Function Start/End"), wxT("CDlgMessages::RestoreState - Function End"));
    return true;
}


void CDlgMessages::RestoreWindowDimensions() {
    wxString        strBaseConfigLocation = wxString(wxT("/Simple/Messages"));
    wxConfigBase*   pConfig = wxConfigBase::Get(FALSE);
    bool            bWindowIconized = false;
    bool            bWindowMaximized = false;
    int             iHeight = 0;
    int             iWidth = 0;
    int             iTop = 0;
    int             iLeft = 0;

    wxASSERT(pConfig);

    pConfig->SetPath(strBaseConfigLocation);

    pConfig->Read(wxT("YPos"), &iTop, 30);
    pConfig->Read(wxT("XPos"), &iLeft, 30);
    pConfig->Read(wxT("Width"), &iWidth, 640);
    pConfig->Read(wxT("Height"), &iHeight, 480);
    pConfig->Read(wxT("WindowIconized"), &bWindowIconized, false);
    pConfig->Read(wxT("WindowMaximized"), &bWindowMaximized, false);

#ifndef __WXMAC__

    Iconize(bWindowIconized);
    Maximize(bWindowMaximized);
    if (!IsIconized() && !IsMaximized()) {
        SetSize(-1, -1, iWidth, iHeight);
    }

#else   // ! __WXMAC__

    // If the user has changed the arrangement of multiple 
    // displays, make sure the window title bar is still on-screen.
    Rect titleRect = {iTop, iLeft, iTop+22, iLeft+iWidth };
    InsetRect(&titleRect, 5, 5);    // Make sure at least a 5X5 piece visible
    RgnHandle displayRgn = NewRgn();
    CopyRgn(GetGrayRgn(), displayRgn);  // Region encompassing all displays
    Rect menuRect = ((**GetMainDevice())).gdRect;
    menuRect.bottom = GetMBarHeight() + menuRect.top;
    RgnHandle menuRgn = NewRgn();
    RectRgn(menuRgn, &menuRect);                // Region hidden by menu bar
    DiffRgn(displayRgn, menuRgn, displayRgn);   // Subtract menu bar retion
    if (!RectInRgn(&titleRect, displayRgn))
        iTop = iLeft = 30;
    DisposeRgn(menuRgn);
    DisposeRgn(displayRgn);

    SetSize(iLeft, iTop, iWidth, iHeight);

#endif  // ! __WXMAC__
}

