/* 
 * © 2009 Sun Microsystems, Inc.
 *
 * 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 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., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */
#include "stdafx.h"
#include "wf_wizard.h"

/**
 * Implementation of the mforms wizard form.
 */

using namespace std;
using namespace MySQL::Forms;

//----------------- WizardImpl static functions ----------------------------------------------------

bool WizardImpl::create(::mforms::Wizard *self)
{
  WizardImpl ^wizard= gcnew WizardImpl(self);

  if (wizard != nullptr)
    return true;
  return false;
}

//--------------------------------------------------------------------------------------------------

void WizardImpl::set_title(::mforms::Wizard* self, const string& title)
{
  WizardImpl^ wizard= (WizardImpl^)ObjectImpl::FromUnmanaged(self);
  if (wizard != nullptr)
    wizard->set_title(title);
}

//--------------------------------------------------------------------------------------------------

void WizardImpl::run_modal(::mforms::Wizard* self)
{
  WizardImpl^ wizard= (WizardImpl^)ObjectImpl::FromUnmanaged(self);
  if (wizard != nullptr)
    wizard->run_modal();
}

//--------------------------------------------------------------------------------------------------

void WizardImpl::close(::mforms::Wizard* self)
{
  WizardImpl^ wizard= (WizardImpl^)ObjectImpl::FromUnmanaged(self);
  if (wizard != nullptr)
    return wizard->close();
}

//--------------------------------------------------------------------------------------------------

void WizardImpl::flush_events(::mforms::Wizard* self)
{
  WizardImpl^ wizard= (WizardImpl^)ObjectImpl::FromUnmanaged(self);
  if (wizard != nullptr)
    wizard->flush_events();
}

//--------------------------------------------------------------------------------------------------

void WizardImpl::set_content(::mforms::Wizard* self, ::mforms::View* view)
{
  WizardImpl^ wizard= (WizardImpl^)ObjectImpl::FromUnmanaged(self);
  if (wizard != nullptr)
    wizard->set_content(view);
}

//--------------------------------------------------------------------------------------------------

void WizardImpl::set_heading(::mforms::Wizard* self, const string& heading)
{
  WizardImpl^ wizard= (WizardImpl^)ObjectImpl::FromUnmanaged(self);
  if (wizard != nullptr)
    wizard->set_heading(heading);
}

//--------------------------------------------------------------------------------------------------

void WizardImpl::set_step_list(::mforms::Wizard* self, const vector<string>& steps)
{
  WizardImpl^ wizard= (WizardImpl^)ObjectImpl::FromUnmanaged(self);
  if (wizard != nullptr)
    wizard->set_step_list(steps);
}

//--------------------------------------------------------------------------------------------------

void WizardImpl::set_allow_cancel(::mforms::Wizard* self, bool flag)
{
  WizardImpl^ wizard= (WizardImpl^)ObjectImpl::FromUnmanaged(self);
  if (wizard != nullptr)
    wizard->set_allow_cancel(flag);
}

//--------------------------------------------------------------------------------------------------

void WizardImpl::set_allow_back(::mforms::Wizard* self, bool flag)
{
  WizardImpl^ wizard= (WizardImpl^)ObjectImpl::FromUnmanaged(self);
  if (wizard != nullptr)
    wizard->set_allow_back(flag);
}

//--------------------------------------------------------------------------------------------------

void WizardImpl::set_allow_next(::mforms::Wizard* self, bool flag)
{
  WizardImpl^ wizard= (WizardImpl^)ObjectImpl::FromUnmanaged(self);
  if (wizard != nullptr)
    wizard->set_allow_next(flag);
}

//--------------------------------------------------------------------------------------------------

void WizardImpl::set_show_extra(::mforms::Wizard* self, bool flag)
{
  WizardImpl^ wizard= (WizardImpl^)ObjectImpl::FromUnmanaged(self);
  if (wizard != nullptr)
    wizard->set_show_extra(flag);
}

//--------------------------------------------------------------------------------------------------

void WizardImpl::set_extra_caption(::mforms::Wizard* self, const string& caption)
{
  WizardImpl^ wizard= (WizardImpl^)ObjectImpl::FromUnmanaged(self);
  if (wizard != nullptr)
    wizard->set_extra_caption(caption);
}

//--------------------------------------------------------------------------------------------------

void WizardImpl::set_next_caption(::mforms::Wizard* self, const string& caption)
{
  WizardImpl^ wizard= (WizardImpl^)ObjectImpl::FromUnmanaged(self);
  if (wizard != nullptr)
    wizard->set_next_caption(caption);
}

//----------------- WizardImpl actual implementation -----------------------------------------------

WizardImpl::WizardImpl(::mforms::Wizard* self)
  : ObjectImpl(self)
{
  _main= gcnew Form;
  _sidebar= gcnew FlowLayoutPanel;
  _title= gcnew Label;
  _extra_button= gcnew Button;
  _footer= gcnew TableLayoutPanel;
  _button_bar= gcnew FlowLayoutPanel;
  _back_button= gcnew Button;
  _next_button= gcnew Button;
  _cancel_button= gcnew Button;
  _content= gcnew Panel;

  _sidebar_overlay= Image::FromFile("images/ui/wb-wizard-vista-bg.png");

  // Main form, the dialog itself.
  _main->BackColor= Color::White;
  _main->FormBorderStyle = ::FormBorderStyle::SizableToolWindow;
  _main->MaximizeBox = false;      
  _main->MinimizeBox = false;
  _main->StartPosition = FormStartPosition::CenterScreen;
  _main->CancelButton= _cancel_button;
  _main->Resize += gcnew EventHandler(resize);
  _main->Tag= gcnew IntPtr(self);

  // The footer with buttons.
  _main->Controls->Add(_footer);
  _footer->RowCount= 1;
  _footer->ColumnCount= 2;
  _footer->AutoSize= true;
  _footer->Dock= DockStyle::Bottom;
  _footer->Padding= Padding(10);
  _footer->Controls->Add(_extra_button, 0, 0);

  _button_bar->FlowDirection= FlowDirection::RightToLeft;
  _button_bar->Controls->Add(_cancel_button);
  _button_bar->Controls->Add(_next_button);
  _button_bar->Controls->Add(_back_button);
  _button_bar->Dock= DockStyle::Right;
  _button_bar->AutoSize= true;
  _button_bar->Margin= Padding(0);
  _footer->Controls->Add(_button_bar, 1, 0);

  // We need to keep a reference to the wizard in the buttons to be able
  // to notify it when the buttons are clicked.
  _back_button->Tag= gcnew IntPtr(self);
  _back_button->Text= "&Back";
  _back_button->UseMnemonic= true;
  _back_button->Click += gcnew EventHandler(backClick);

  _next_button->Tag= gcnew IntPtr(self);
  _next_button->Text= "&Next";
  _next_button->UseMnemonic= true;
  _next_button->Click += gcnew EventHandler(nextClick);

  _cancel_button->Tag= gcnew IntPtr(self);
  _cancel_button->Text= "&Cancel";
  _cancel_button->UseMnemonic= true;
  _cancel_button->Click += gcnew EventHandler(cancelClick);

  _extra_button->Tag= gcnew IntPtr(self);
  _extra_button->Text= "&Advanced";
  _extra_button->UseMnemonic= true;
  _extra_button->Click += gcnew EventHandler(extraClick);

  // The side bar with background painting and list of strings.
  _main->Controls->Add(_sidebar);
  _sidebar->Tag= gcnew IntPtr(self);
  _sidebar->Dock= DockStyle::Left;
  _sidebar->ForeColor= Color::White;
  _sidebar->Paint += gcnew PaintEventHandler(sidebarPaint);

  // Title
  _main->Controls->Add(_title);
  _title->AutoSize= false;
  _title->Font= gcnew Font("Tahoma", 12.0, FontStyle::Bold, GraphicsUnit::Pixel);
  _title->ForeColor= ColorTranslator::FromHtml("#003392");
  _title->Location= Point(_sidebar->Width, 0);
  _title->Padding= Padding(15);

  // Other initialization.
  _main->Controls->Add(_content);

  // Resize as last action. Triggers layouting of the elements.
  _main->Size= Size(800, 600); 
}

//--------------------------------------------------------------------------------------------------

/**
 * Used to draw a gradient background for the side bar.
 *
 * @param sender The control for which the paint event is triggered (the side bar).
 * @param arguments Additional data needed to paint the background.
 */
void WizardImpl::sidebarPaint(Object^ sender, PaintEventArgs^ arguments)
{
  FlowLayoutPanel^ panel= (FlowLayoutPanel^) sender;
  Graphics^ g= arguments->Graphics;

  Drawing::Drawing2D::LinearGradientBrush gradientBrush(
    Point(10, 0),
    Point(10, panel->Height),
    Color::FromArgb(255, 66, 111, 166),
    Color::FromArgb(255, 103, 186, 104));

  ::mforms::Wizard* wizard= ViewImpl::get_backend_control<::mforms::Wizard>(panel);
  WizardImpl^ wizard_impl= (WizardImpl^)ObjectImpl::FromUnmanaged(wizard);

  g->FillRectangle(%gradientBrush, 0, 0, panel->Width, panel->Height);
  g->DrawImage(wizard_impl->_sidebar_overlay, 0, panel->Height - wizard_impl->_sidebar_overlay->Height);
}

//--------------------------------------------------------------------------------------------------

void WizardImpl::nextClick(Object^ sender, EventArgs^ arguments)
{
  Windows::Forms::Button^ btn= (Windows::Forms::Button^)sender;

  if (btn->Tag != nullptr)
  {
    ::mforms::Wizard* wizard= ViewImpl::get_backend_control<::mforms::Wizard>(btn);
    if (wizard != NULL)
      wizard->next_clicked();
  }
}

//--------------------------------------------------------------------------------------------------

void WizardImpl::backClick(Object^ sender, EventArgs^ arguments)
{
  Windows::Forms::Button^ btn= (Windows::Forms::Button^)sender;

  if (btn->Tag != nullptr)
  {
    ::mforms::Wizard* wizard= ViewImpl::get_backend_control<::mforms::Wizard>(btn);
    if (wizard != NULL)
      wizard->back_clicked();
  }
}

//--------------------------------------------------------------------------------------------------

void WizardImpl::cancelClick(Object^ sender, EventArgs^ arguments)
{
  Windows::Forms::Button^ btn= (Windows::Forms::Button^)sender;

  if (btn->Tag != nullptr)
  {
    ::mforms::Wizard* wizard= ViewImpl::get_backend_control<::mforms::Wizard>(btn);
    if (wizard != NULL && wizard->_cancel_slot())
      ((Form^) btn->TopLevelControl)->Close();
  }
}

//--------------------------------------------------------------------------------------------------

void WizardImpl::extraClick(Object^ sender, EventArgs^ arguments)
{
  Windows::Forms::Button^ btn= (Windows::Forms::Button^)sender;

  if (btn->Tag != nullptr)
  {
    ::mforms::Wizard* wizard= ViewImpl::get_backend_control<::mforms::Wizard>(btn);
    if (wizard != NULL)
      wizard->extra_clicked();
  }
}

//--------------------------------------------------------------------------------------------------

void WizardImpl::resize(Object^ sender, EventArgs^ arguments)
{
  ::mforms::Wizard* wizard= ViewImpl::get_backend_control<::mforms::Wizard>((Form^) sender);
  WizardImpl^ wizard_impl= (WizardImpl^)ObjectImpl::FromUnmanaged(wizard);

  Drawing::Rectangle area= wizard_impl->_main->DisplayRectangle;
  wizard_impl->_title->Size= Size(area.Width - wizard_impl->_sidebar->Width, 50);
  wizard_impl->_title->Location= Point(wizard_impl->_sidebar->Width, 0);

  wizard_impl->_content->Size= Size(area.Width - wizard_impl->_sidebar->Width, 
    area.Height - wizard_impl->_footer->Height - wizard_impl->_title->Height);
  wizard_impl->_content->Location= Point(wizard_impl->_sidebar->Width, wizard_impl->_title->Height);
}

//--------------------------------------------------------------------------------------------------

void WizardImpl::set_title(const string& title)
{
  _main->Text= CppStringToNative(title);
}

//--------------------------------------------------------------------------------------------------

void WizardImpl::run_modal()
{
  _main->ShowDialog();
}

//--------------------------------------------------------------------------------------------------

void WizardImpl::close()
{
  _main->Close();
}

//--------------------------------------------------------------------------------------------------

void WizardImpl::flush_events()
{
  Application::DoEvents();
}

//--------------------------------------------------------------------------------------------------

void WizardImpl::set_content(::mforms::View *view)
{
  // Remove old stuff if there is some.
  if (_content->Controls->Count > 0)
  {
    _content->Controls[0]->Dock= DockStyle::None;
    _content->Controls->Clear();
  }

  if (view != NULL)
  {
    ViewImpl^ new_content_view= (ViewImpl^)ObjectImpl::FromUnmanaged(view);
    view->set_resize_mode(::mforms::ResizeNone);
    Control^ new_content= new_content_view->get_control<Control>();

    _content->Controls->Add(new_content);
    new_content->Dock= DockStyle::Fill;
  }
}

//--------------------------------------------------------------------------------------------------

void WizardImpl::set_heading(const string& heading)
{
  _title->Text= CppStringToNative(heading);
}

//--------------------------------------------------------------------------------------------------

void WizardImpl::set_step_list(const vector<string>& steps)
{
  // Remove old list.
  _main->SuspendLayout();
  try
  {
    _sidebar->Controls->Clear();

    for each (string entry in steps)
    {
      Label^ label= gcnew Label();
      label->Text= CppStringToNative(entry.substr(1));
      FontStyle style= FontStyle::Regular;
      switch (entry[0])
      {
      case '*': // current task
        label->ForeColor= Color::White;
        style= FontStyle::Bold;
        break;
      case '.': // executed task
        label->ForeColor= Color::White;
        break;
      case '-': // open task
        label->ForeColor= Color::FromArgb(255, 192, 192, 192);
        break;
      }
      label->Font=  gcnew Font("Tahoma", 11.0, style, GraphicsUnit::Pixel);
      label->BackColor= Color::Transparent;
      label->Padding= Padding(7);
      label->Size= Size(_sidebar->Width, label->PreferredHeight);
      _sidebar->Controls->Add(label);
    }
  }
  finally
  {
    _main->ResumeLayout();
  }
}

//--------------------------------------------------------------------------------------------------

void WizardImpl::set_allow_cancel(bool flag)
{
  _cancel_button->Enabled= flag;
}

//--------------------------------------------------------------------------------------------------

void WizardImpl::set_allow_back(bool flag)
{
  _back_button->Enabled= flag;
}

//--------------------------------------------------------------------------------------------------

void WizardImpl::set_allow_next(bool flag)
{
  _next_button->Enabled= flag;
}

//--------------------------------------------------------------------------------------------------

void WizardImpl::set_show_extra(bool flag)
{
  _extra_button->Visible= flag;
}

//--------------------------------------------------------------------------------------------------

void WizardImpl::set_extra_caption(const string& caption)
{
  _extra_button->Text= CppStringToNative(caption);
}

//--------------------------------------------------------------------------------------------------

void WizardImpl::set_next_caption(const string& caption)
{
  if (caption.size() == 0)
    _next_button->Text= "&Next";
  else
    _next_button->Text= CppStringToNative(caption)->Replace("_", "&");
}

//--------------------------------------------------------------------------------------------------

