/* 
 * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; version 2 of the
 * License.
 * 
 * This program 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 General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301  USA
 */

/**
 * Implementation of the mforms tabview control for Windows.
 */

#include "stdafx.h"

#include "mforms/mforms.h"
#include "wf_view.h"
#include "wf_tabview.h"
#include "wf_panel.h"

#include "ConvUtils.h"

using namespace System::Drawing;
using namespace System::Windows::Forms;

using namespace MySQL;
using namespace MySQL::Forms;
using namespace MySQL::Controls;
using namespace MySQL::Utilities;

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

/**
 * Helper method for basic setup of a flat tabview glued to the backend tabview by the given wrapper.
 */
FlatTabControl^ createFlatTabControl(mforms::TabView* beTabview, TabViewImpl ^wrapperTabview) 
{
  FlatTabControl^ result = ViewImpl::create<FlatTabControl>(beTabview, wrapperTabview);

  result->UpdateColors();

  // Setting the background here for all tabviews might conflict with special usage,
  // but so far all our tabviews are on a main background.
  result->BackgroundColor = Conversions::GetApplicationColor(ApplicationColor::AppColorMainBackground, false);
  result->CanCloseLastTab = false;
  result->HideWhenEmpty = false;
  result->ItemPadding = Padding(6, 0, 6, 0);
  result->ItemSize = Size(0, 21);
  result->Margin = Padding(6, 0, 6, 0);

  return result;
}

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

TabViewImpl::TabViewImpl(mforms::TabView *self, mforms::TabViewType type)
: ViewImpl(self), _tabType(type), _active_index(-1)
{
}

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

bool TabViewImpl::create(mforms::TabView *self, mforms::TabViewType type)
{
  TabViewImpl ^tabview= gcnew TabViewImpl(self, type);

  if (tabview != nullptr)
  {
    switch (type)
    {
    case mforms::TabViewTabless:
        ViewImpl::create<FillPanel>(self, tabview);
        break;

    // case mforms::TabViewMain:
    //   break;

    case mforms::TabViewMainClosable:
      {
        FlatTabControl^ tabControl = createFlatTabControl(self, tabview);

        tabControl->ContentPadding = Padding(0, 6, 0, 6);
        tabControl->ShowCloseButton = true;
        tabControl->ShowFocusState = false;
        tabControl->TabStyle = FlatTabControl::TabStyleType::TopTransparent;

        tabControl->Selected += gcnew TabControlEventHandler(&TabViewImpl::tab_changed);
        tabControl->TabClosing += gcnew EventHandler<TabClosingEventArgs^>(&TabViewImpl::tab_closing);
        tabControl->TabClosed += gcnew EventHandler<TabClosedEventArgs^>(&TabViewImpl::tab_closed);

        break;
      }

    case mforms::TabViewDocument:
    case mforms::TabViewDocumentClosable:
      {
        FlatTabControl^ tabControl = createFlatTabControl(self, tabview);

        tabControl->Margin = Padding(0);
        tabControl->ShowCloseButton = type == mforms::TabViewDocumentClosable;
        tabControl->ShowFocusState = true;
        tabControl->TabStyle = FlatTabControl::TabStyleType::TopNormal;
        tabControl->ContentPadding = Padding(0, 4, 0, 0);

        tabControl->Selected += gcnew TabControlEventHandler(&TabViewImpl::tab_changed);
        tabControl->TabClosing += gcnew EventHandler<TabClosingEventArgs^>(&TabViewImpl::tab_closing);
        tabControl->TabClosed += gcnew EventHandler<TabClosedEventArgs^>(&TabViewImpl::tab_closed);

        break;
      }
      
    case mforms::TabViewPalette:
    case mforms::TabViewSelectorSecondary:
      {
        FlatTabControl^ tabControl = createFlatTabControl(self, tabview);

        tabControl->Margin = Padding(0);
        tabControl->ItemSize = Size(0, 19);
        tabControl->ShowCloseButton = false;
        tabControl->ShowFocusState = false;
        tabControl->TabStyle = FlatTabControl::TabStyleType::BottomNormal;

        tabControl->Selected += gcnew TabControlEventHandler(&TabViewImpl::tab_changed);
        tabControl->TabClosing += gcnew EventHandler<TabClosingEventArgs^>(&TabViewImpl::tab_closing);
        tabControl->TabClosed += gcnew EventHandler<TabClosedEventArgs^>(&TabViewImpl::tab_closed);

        break;
      }

    default: // mforms::TabViewSystemStandard
      TabControl^ control= ViewImpl::create<TabControl>(self, tabview);

      // Listen to tab changes by the user.
      control->Selected += gcnew TabControlEventHandler(&TabViewImpl::tab_changed);
    }
    return true;
  }
  return false;
}

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

void TabViewImpl::set_active_tab(mforms::TabView *self, int index)
{
  TabViewImpl^ tabview = (TabViewImpl^)ObjectImpl::FromUnmanaged(self);

  if (tabview != nullptr)
  {
    if (tabview->_tabType == mforms::TabViewTabless)
    {
      if (index < 0)
        index= 0;
      if (index > tabview->_pages.Count - 1)
        index= tabview->_pages.Count - 1;

      if (tabview->_active_index != index)
      {
        tabview->_active_index= index;

        FillPanel^ content_container = tabview->get_control<FillPanel>();
        content_container->Controls->Clear();

        Control^ page_container = tabview->_pages[index]->get_control<Control>();
        content_container->Controls->Add(page_container);
        page_container->Dock = DockStyle::Fill;

        // Explicitly trigger a new relayout with a reason that is handled.
        content_container->PerformLayout(content_container, "Bounds");
      }
    }
    else
      tabview->get_control<TabControl>()->SelectedIndex= index;

    (*self->signal_tab_changed())();

    self->set_layout_dirty(true);
  }
}

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

int TabViewImpl::get_active_tab(mforms::TabView *self)
{
  TabViewImpl^ tabview= (TabViewImpl^)ObjectImpl::FromUnmanaged(self);

  if (tabview != nullptr)
  {
    if (tabview->_tabType == mforms::TabViewTabless)
      return tabview->_active_index;
    else
      return tabview->get_control<TabControl>()->SelectedIndex;
  }
  return -1;
}

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

int TabViewImpl::add_page(mforms::TabView *self, mforms::View *page, const std::string& caption)
{
  TabViewImpl^ tabview= (TabViewImpl^) ObjectImpl::FromUnmanaged(self);

  int new_index = -1;

  if (tabview != nullptr)
  {
    ViewImpl^ view = (ViewImpl^)ObjectImpl::FromUnmanaged(page);
    view->set_resize_mode(AutoResizeMode::ResizeNone);

    if (tabview->_tabType == mforms::TabViewTabless)
    {
      ViewImpl^ view= (ViewImpl^) ObjectImpl::FromUnmanaged(page);
      tabview->_pages.Add(view);
    // Don't set bg color here since it will override the color set for the tab before adding it
    //view->get_control()->BackColor = Color::Transparent;

      new_index = tabview->_pages.Count - 1;
    }
    else
    {
      TabPage^ tabPage= gcnew TabPage();

      Control^ control= view->get_control<Control>();
      control->Dock = DockStyle::Fill;
      tabPage->Controls->Add(control);
      tabPage->Text= CppStringToNative(caption);
      tabPage->BackColor = control->BackColor;

      TabControl^ tabControl= tabview->get_control<TabControl>();
      tabControl->TabPages->Add(tabPage);

      new_index= tabControl->TabPages->Count - 1;
    }

    // Set the page as active page if this is the first page that was added.
    if (new_index == 0)
      set_active_tab(self, new_index);

    self->set_layout_dirty(true);
  }
  return new_index;
}

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

void TabViewImpl::remove_page(mforms::TabView *self, mforms::View *page)
{
  TabViewImpl^ tabview = (TabViewImpl^) ObjectImpl::FromUnmanaged(self);

  if (tabview != nullptr)
  {
    ViewImpl^ view = (ViewImpl^)ObjectImpl::FromUnmanaged(page);

    if (tabview->_tabType == mforms::TabViewTabless)
      tabview->_pages.Remove(view);
    else
    {
      Control^ control= view->get_control<Control>();

      TabControl^ tabControl= tabview->get_control<TabControl>();
      for each (TabPage^ native_page in tabControl->TabPages)
      {
        if (native_page->Controls->Count > 0 && native_page->Controls[0] == control)
        {
          tabControl->TabPages->Remove(native_page);
          break;
        }
      }
    }
    self->set_layout_dirty(true);
  }
}

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

void TabViewImpl::set_tab_title(mforms::TabView *self, int tab, const std::string& caption)
{
  TabViewImpl^ tabview = (TabViewImpl^) ObjectImpl::FromUnmanaged(self);

  if (tabview != nullptr)
  {
    TabControl^ tabControl= tabview->get_control<TabControl>();
    if (tabControl != nullptr)
    {
      if (tab >= 0 && tab < tabControl->TabPages->Count)
        tabControl->TabPages[tab]->Text= CppStringToNative(caption);
    }
  }
}

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

void TabViewImpl::tab_changed(System::Object^ sender, TabControlEventArgs^ e)
{
  Windows::Forms::TabControl^ control= (Windows::Forms::TabControl^) sender;

  if (control->Tag != nullptr)
  {
    mforms::TabView* tabview= ViewImpl::get_backend_control<mforms::TabView>(control);
    if (tabview != NULL)
      (*tabview->signal_tab_changed())();
  }
}

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

void TabViewImpl::tab_closing(System::Object^ sender, TabClosingEventArgs^ e)
{
  Windows::Forms::TabControl^ control= (Windows::Forms::TabControl^) sender;

  if (control->Tag != nullptr)
  {
    mforms::TabView* tabview= ViewImpl::get_backend_control<mforms::TabView>(control);
    if (tabview != NULL)
      e->canClose = tabview->can_close_tab(e->page->TabIndex);
  }
}

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

void TabViewImpl::tab_closed(System::Object^ sender, TabClosedEventArgs^ e)
{
  Windows::Forms::TabControl^ control= (Windows::Forms::TabControl^) sender;

  if (control->Tag != nullptr)
  {
    mforms::TabView* tabview= ViewImpl::get_backend_control<mforms::TabView>(control);
    if (tabview != NULL)
      (*tabview->signal_tab_closed())(e->page->TabIndex);
  }
}

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