/* 
 * 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 label wrapper for the mforms library.
 */

#include "stdafx.h"

#include "mforms/mforms.h"
#include "wf_view.h"
#include "wf_label.h"

#include "base/log.h"
#include "ConvUtils.h"

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

using namespace MySQL::Forms;

DEFAULT_LOG_DOMAIN(DOMAIN_MFORMS_WRAPPER)

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

/**
 * Converts an mform alignment value into a Windows::Forms alignment value.
 */
ContentAlignment get_alignment(mforms::Alignment align)
{
  switch (align)
  {
  case mforms::BottomLeft: 
    return ContentAlignment::BottomLeft;
  case mforms::BottomCenter: 
    return ContentAlignment::BottomCenter;
  case mforms::BottomRight: 
    return ContentAlignment::BottomRight;
  case mforms::MiddleLeft: 
    return ContentAlignment::MiddleLeft;
  case mforms::MiddleCenter: 
    return ContentAlignment::MiddleCenter;
  case mforms::MiddleRight: 
    return ContentAlignment::MiddleRight;
  case mforms::TopLeft: 
    return ContentAlignment::TopLeft;
  case mforms::TopCenter: 
    return ContentAlignment::TopCenter;
  case mforms::TopRight: 
    return ContentAlignment::TopRight;
  }
  return ::System::Drawing::ContentAlignment::TopLeft;
}

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

WrapControlLabel::WrapControlLabel()
{
  autoWrapping = false;
  lastSize = Drawing::Size(-1, -1);
}

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

void WrapControlLabel::Text::set(String ^value)
{
  __super::set(value);
  lastSize = Drawing::Size(-1, -1);
}

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

void WrapControlLabel::Font::set(Drawing::Font ^value)
{
  __super::set(value);
  lastSize = Drawing::Size(-1, -1);
}

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

/**
 * Returns the preferred size of the label depending on its auto-wrapping mode.
 */
Drawing::Size WrapControlLabel::GetPreferredSize(Drawing::Size proposedSize)
{
  System::Drawing::Size result;
  if (!autoWrapping)
  {
    // Default behavior, just let the control itself determine what it needs.
    // Don't use the proposed size, however, or the returned size will always be of the given
    // width (which may lead to wrapping we don't want).
    result = Label::GetPreferredSize(Drawing::Size::Empty);
  }
  else
  {
    // We use the minimal size if the proposed size is too small to allow computation also
    // for containers which have a priori no proper width yet (e.g. tables).
    // This will help us to solve the chicken-egg problem we have (table needs width, but wrapped label too)
    // and at the same time properly involves our minimum size.
    if (proposedSize.Width < MinimumSize.Width)
      proposedSize.Width= MinimumSize.Width;
    if (proposedSize.Height < MinimumSize.Height)
      proposedSize.Height= MinimumSize.Height;

    if (lastSize.Width == proposedSize.Width)
      return lastSize;

    if (proposedSize.Width == 0)
      result= System::Drawing::Size(0, 0);
    else
    {
      TextFormatFlags flags = TextFormatFlags::NoPadding | TextFormatFlags::WordBreak | TextFormatFlags::Left
        | TextFormatFlags::Top;
      result = TextRenderer::MeasureText(Text, Font, System::Drawing::Size(proposedSize.Width, 0), flags);
    }
  };

  // Make sure we don't go smaller than our minimal size anyway.
  if (result.Width < MinimumSize.Width)
    result.Width = MinimumSize.Width;
  if (result.Height< MinimumSize.Height)
    result.Height = MinimumSize.Height;

  lastSize = result;

  return result;
}

//----------------- Static functions ---------------------------------------------------------------

bool LabelImpl::create(mforms::Label *self)
{
  LabelImpl ^label= gcnew LabelImpl(self);

  if (label != nullptr)
  {
    WrapControlLabel^ l= ViewImpl::create<WrapControlLabel>(self, label);
    l->TextAlign= ContentAlignment::MiddleLeft;
    l->BorderStyle= BorderStyle::None;
    l->ForeColor = Color::Black;
    return true;
  }
  return false;
}

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

void LabelImpl::set_style(mforms::Label *self, mforms::LabelStyle style)
{
  LabelImpl^ label= (LabelImpl^)ObjectImpl::FromUnmanaged(self);

  if (label != nullptr)
    label->set_style(style);
}

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

void LabelImpl::set_text(mforms::Label *self, const std::string &text)
{
  LabelImpl^ label= (LabelImpl^)ObjectImpl::FromUnmanaged(self);

  if (label != nullptr)
  {
    if (!text.empty() && text[text.size() - 1] == '\n') // Add a space if there's a trailing linebreak. Otherwise it would be ignored.
      label->set_text(text + " ");
    else
      label->set_text(text);
    self->set_layout_dirty(true);
  }
}

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

void LabelImpl::set_text_align(mforms::Label *self, mforms::Alignment align)
{
  LabelImpl^ label= (LabelImpl^)ObjectImpl::FromUnmanaged(self);

  if (label != nullptr)
  {
    label->set_text_align(align);
    self->set_layout_dirty(true);
  }
}

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

void LabelImpl::set_color(mforms::Label *self, const std::string &color)
{
  LabelImpl^ label= (LabelImpl^)ObjectImpl::FromUnmanaged(self);

  if (label != nullptr)
    label->set_color(color);
}

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

void LabelImpl::set_wrap_text(mforms::Label *self, bool flag)
{
  LabelImpl^ label= (LabelImpl^)ObjectImpl::FromUnmanaged(self);

  if (label != nullptr)
  {
    label->set_wrap_text(flag);
    self->set_layout_dirty(true);
  }
}

//----------------- Actual implementation ----------------------------------------------------------

LabelImpl::LabelImpl(mforms::Label *self)
  : ViewImpl(self)
{
}

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

void LabelImpl::set_style(mforms::LabelStyle style)
{
  WrapControlLabel^ label= get_control<WrapControlLabel>();

  try
  {
    switch (style)
    {
    case mforms::NormalStyle:
      label->Font= gcnew Font(DEFAULT_FONT, DEFAULT_FONT_SIZE, FontStyle::Regular, GraphicsUnit::Pixel);
      break;
    case mforms::BoldStyle: 
      label->Font= gcnew Font(DEFAULT_FONT, DEFAULT_FONT_SIZE, FontStyle::Bold, GraphicsUnit::Pixel);
      break;
    case mforms::BigStyle:
      label->Font= gcnew Font(DEFAULT_FONT, DEFAULT_FONT_SIZE + 4, FontStyle::Regular, GraphicsUnit::Pixel);
      break;
    case mforms::BigBoldStyle:
      label->Font= gcnew Font(DEFAULT_FONT, DEFAULT_FONT_SIZE + 4, FontStyle::Bold, GraphicsUnit::Pixel);
      break;
    case mforms::SmallBoldStyle:
      label->Font= gcnew Font(DEFAULT_FONT, 8, FontStyle::Bold, GraphicsUnit::Pixel);
      break;
    case mforms::SmallStyle:
      label->Font= gcnew Font(DEFAULT_FONT, 8, FontStyle::Regular, GraphicsUnit::Point);
      break;
    case mforms::VerySmallStyle:
      label->Font= gcnew Font(DEFAULT_SMALL_FONT, 7.5, FontStyle::Regular, GraphicsUnit::Point);
      break;
    case mforms::InfoCaptionStyle:
      label->Font= gcnew Font(DEFAULT_FONT, label->Font->Size, FontStyle::Regular, GraphicsUnit::Pixel);
      break;
    case mforms::BoldInfoCaptionStyle:
      label->Font= gcnew Font(DEFAULT_FONT, label->Font->Size, FontStyle::Bold, GraphicsUnit::Pixel);
      break;
    case mforms::WizardHeadingStyle:
      label->Font= gcnew Font(DEFAULT_FONT, 12.0, FontStyle::Bold, GraphicsUnit::Pixel);
      label->ForeColor= ColorTranslator::FromHtml("#003392");
      break;
    case mforms::SmallHelpTextStyle:
      label->Font= gcnew Font(DEFAULT_FONT, 11, FontStyle::Regular, GraphicsUnit::Pixel);
      break;
    case mforms::VeryBigStyle:
      label->Font= gcnew Font(DEFAULT_FONT, 13, FontStyle::Regular, GraphicsUnit::Point);
      break;
    }

    Size newSize = label->PreferredSize;
    if (label->AutoWrapping)
      newSize.Width = label->Size.Width;
    label->Size = newSize;
  }
  catch (System::ArgumentException^ e)
  {
    // Argument exception pops up when the system cannot find the Regular font style (corrupt font).
    log_error("LabelImpl::set_style failed. %s\n", e->Message);
  }
}

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

void LabelImpl::set_text(const std::string &text)
{
  String^ new_text = CppStringToNative(text);
  WrapControlLabel^ label = get_control<WrapControlLabel>();
  if (label->Text != new_text)
  {
    label->Text = new_text;

    Size newSize = label->PreferredSize;
    if (label->AutoWrapping)
      newSize.Width = label->Size.Width;
    label->Size = newSize;
  };
}

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

void LabelImpl::set_text_align(mforms::Alignment align)
{
  get_control<WrapControlLabel>()->TextAlign = get_alignment(align);
}

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

void LabelImpl::set_color(const std::string &color)
{
  get_control<WrapControlLabel>()->ForeColor = ColorTranslator::FromHtml(CppStringToNative(color));
}

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

void LabelImpl::set_wrap_text(bool flag)
{
  get_control<WrapControlLabel>()->AutoWrapping = flag;
}

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

