/*
 * File:	wx_rbox.cc
 * Purpose:	Radio box item implementation
 * Author:	Julian Smart
 * Created:	1993
 * Updated:	April 1995
 * Copyright:	(c) 1995, AIAI, University of Edinburgh
 */

/* static const char sccsid[] = "%W% %G%"; */

#if !defined(_MSC_VER) && !defined(wx_wxh)
#define wx_wxh
#endif

#include "wx.h"
#pragma hdrstop

#include "wx_panel.h"
#include "wx_rbox.h"
#include "wx_itemp.h"

BOOL wxRadioBox::MSWCommand(UINT param, WORD id)
{
  if (param == BN_CLICKED)
  {
#ifdef WIN32
    for (int i = 0; i < no_items; i++)
      if (id == GetWindowLong(radioButtons[i], GWL_ID))
        selected = i;
#else
    for (int i = 0; i < no_items; i++)
      if (id == GetWindowWord(radioButtons[i], GWW_ID))
        selected = i;
#endif

    wxCommandEvent event(wxEVENT_TYPE_RADIOBOX_COMMAND);
    event.commandInt = selected;
    event.eventObject = this;
    ProcessCommand(event);
    return TRUE;
  }
  else return FALSE;
}

// Radio box item
IMPLEMENT_DYNAMIC_CLASS(wxRadioBox, wxItem)

wxRadioBox::wxRadioBox(void)
{
  wxWinType = wxTYPE_HWND;
  static_label = NULL;
  windows_id = 0;
  no_items = 0;
  ms_handle = 0;
  radioButtons = NULL;
  majorDim = 0 ;
  selected = -1;
  radioWidth = NULL ;
  radioHeight = NULL ;
  isFafa = RADIO_IS_FAFA ;
}

wxRadioBox::wxRadioBox(wxPanel *panel, wxFunction func,
                       char *Title,
                       int x, int y, int width, int height,
                       int N, char **Choices,
                       int MajorDim,long style, char *name):
  wxbRadioBox(panel, func, Title, x, y, width, height, N, Choices,
              MajorDim, style, name)
{
  Create(panel, func, Title, x, y, width, height, N, Choices, MajorDim, style, name);
}

/*
 * Causes problems for the Turbo C++ for Windows linker
 *
 */
#ifndef __BORLANDC__
wxRadioBox::wxRadioBox(wxPanel *panel, wxFunction func,
                       char *Title,
                       int x, int y, int width, int height,
                       int N, wxBitmap **Choices,
                       int MajorDim,long style, char *name):
  wxbRadioBox(panel, func, Title, x, y, width, height, N, Choices,
              MajorDim, style, name)
{
  Create(panel, func, Title, x, y, width, height, N, Choices, MajorDim, style, name);
}
#endif

Bool wxRadioBox::Create(wxPanel *panel, wxFunction func,
                       char *Title,
                       int x, int y, int width, int height,
                       int N, char **Choices,
                       int MajorDim, long style, char *name)
{
  SetName(name);
  if (panel) panel->AddChild(this);
  buttonFont = panel->buttonFont ;
  labelFont = panel->labelFont ;
  backColour = panel->backColour ;
  labelColour = panel->labelColour ;
  buttonColour = panel->buttonColour ;
  if (MajorDim==0)
    MajorDim = N ;
  majorDim = MajorDim ;
  windowStyle = style ;
  selected = -1;
  ms_handle = 0;
  isFafa = RADIO_IS_FAFA ;
  static_label = NULL;
  wxWinType = wxTYPE_HWND;
  wxWnd *cparent = NULL;
  if (panel)
    cparent = (wxWnd *)(panel->handle);

//  labelPosition = panel->label_position;
  panel->GetValidPosition(&x, &y);

  char *the_label = NULL ;

  if (Title)
  {
    the_label = new char[strlen(Title)+1] ;
    if (style&wxFIXED_LENGTH)
      for (int i=0;i<(int)strlen(Title);i++)
        the_label[i]=MEANING_CHARACTER ;
    else
      strcpy(the_label,Title) ;
    the_label[strlen(Title)] = '\0' ;
  }
  else the_label=copystring("") ;

  static_label = NULL;
  HWND the_handle ;

  ms_handle = CreateWindow(GROUP_CLASS,Title,
                           GROUP_FLAGS,
                           0,0,0,0,
                           cparent->handle,(HMENU)NewId(),wxhInstance,NULL) ;

  the_handle = cparent->handle ;

#if CTL3D
    Ctl3dSubclassCtl(ms_handle);
#endif
  HDC the_dc = GetWindowDC(ms_handle) ;
  if (labelFont && labelFont->GetInternalFont(the_dc))
    SendMessage(ms_handle,WM_SETFONT,
                (WPARAM)labelFont->GetInternalFont(the_dc),0L);
  ReleaseDC(ms_handle,the_dc) ;

  the_handle = cparent->handle;

  // Subclass again for purposes of dialog editing mode
  SubclassControl((HWND)ms_handle);

  // Some radio boxes test consecutive id.
  (void)NewId() ;
  radioButtons = new HWND[N];
  radioWidth = new int[N] ;
  radioHeight = new int[N] ;
  for (int i = 0; i < N; i++)
  {
    radioWidth[i] = radioHeight[i] = -1 ;
    long groupStyle = 0;
    if (i == 0 && style==0)
      groupStyle = WS_GROUP;
    long newId = NewId();
    radioButtons[i] = CreateWindowEx(0, RADIO_CLASS, Choices[i], 
                          groupStyle | RADIO_FLAGS,0,0,0,0,
                          the_handle, (HMENU)newId, wxhInstance, NULL);
#if CTL3D
    Ctl3dSubclassCtl(radioButtons[i]);
#endif
    HDC the_dc = GetWindowDC((HWND)radioButtons[i]) ;
    if (buttonFont && buttonFont->GetInternalFont(the_dc))
      SendMessage((HWND)radioButtons[i],WM_SETFONT,
                  (WPARAM)buttonFont->GetInternalFont(the_dc),0L);
    ReleaseDC((HWND)radioButtons[i],the_dc) ;
    subControls.Append((wxObject *)newId);
  }
//  (void)NewId() ;
  // Create a dummy radio control to end the group.
  (void)CreateWindowEx(0, RADIO_CLASS, "", WS_GROUP|RADIO_FLAGS, 0,0,0,0, the_handle, (HMENU)NewId(), wxhInstance, NULL);

  no_items = N;
  SetSelection(0);

  SetSize(x, y, width, height);
  panel->AdvanceCursor(this);
  Callback(func);

  if (Title)
  {
    if (style&wxFIXED_LENGTH)
      SetLabel(Title) ;
  }
  if (the_label)
    delete [] the_label ;

  return TRUE;
}

#ifndef __BORLANDC__
Bool wxRadioBox::Create(wxPanel *panel, wxFunction func,
                       char *Title,
                       int x, int y, int width, int height,
                       int N, wxBitmap **Choices,
                       int MajorDim, long style, char *name)
{
  SetName(name);
  if (panel) panel->AddChild(this);
  buttonFont = panel->buttonFont ;
  labelFont = panel->labelFont ;
  backColour = panel->backColour ;
  labelColour = panel->labelColour ;
  buttonColour = panel->buttonColour ;
  if (MajorDim==0)
    MajorDim = N ;
  majorDim = MajorDim ;
  windowStyle = style ;
  selected = -1;
  ms_handle = 0;
  wxWinType = wxTYPE_HWND;
  wxWnd *cparent = NULL;
  if (panel)
    cparent = (wxWnd *)(panel->handle);

  panel->GetValidPosition(&x, &y);

  char *the_label = NULL ;

  if (Title)
  {
    the_label = new char[strlen(Title)+1] ;
    if (style&wxFIXED_LENGTH)
      for (int i=0;i<(int)strlen(Title);i++)
        the_label[i]=MEANING_CHARACTER ;
    else
      strcpy(the_label,Title) ;
    the_label[strlen(Title)] = '\0' ;
  }
  else
    the_label = copystring("") ;

  static_label = NULL;
  HWND the_handle ;

  ms_handle = CreateWindow(GROUP_CLASS,the_label,
                           GROUP_FLAGS,
                           0,0,0,0,
                           cparent->handle,(HMENU)NewId(),wxhInstance,NULL) ;

  HDC the_dc = GetWindowDC(ms_handle) ;
  if (labelFont && labelFont->GetInternalFont(the_dc))
    SendMessage(ms_handle,WM_SETFONT,
                (WPARAM)labelFont->GetInternalFont(the_dc),0L);
  ReleaseDC(ms_handle,the_dc) ;
  the_handle = cparent->handle;

  // Subclass again for purposes of dialog editing mode
  SubclassControl((HWND)ms_handle);

  (void)NewId() ;
  radioButtons = new HWND[N];
  radioWidth = new int[N] ;
  radioHeight = new int[N] ;
#if FAFA_LIB && !CTL3D
  isFafa = TRUE ; //always !!
#else
  isFafa = RADIO_IS_FAFA ;
#endif
  for (int i = 0; i < N; i++)
  {
    long groupStyle = 0;
    if (i == 0 && style==0)
      groupStyle = WS_GROUP;
    long newId = NewId();
#if FAFA_LIB && !CTL3D
    radioWidth[i]  = Choices[i]->GetWidth()  + FB_MARGIN ;
    radioHeight[i] = Choices[i]->GetHeight() + FB_MARGIN ;
#else
    radioWidth[i]  = Choices[i]->GetWidth();
    radioHeight[i] = Choices[i]->GetHeight();
#endif
    char tmp[32] ;
    sprintf(tmp,"Toggle%d",i) ;
#if FAFA_LIB && !CTL3D
    radioButtons[i] = CreateWindowEx(0, FafaChck, tmp,
                          groupStyle | BITRADIO_FLAGS,0,0,0,0,
                          the_handle, (HMENU)newId, wxhInstance, NULL);
    SendMessage((HWND)radioButtons[i],WM_CHANGEBITMAP,
                  (WPARAM)((Choices[i]->GetHeight()<<8)+Choices[i]->GetWidth()),
                  (LPARAM)Choices[i]->ms_bitmap);

#else
    radioButtons[i] = CreateWindowEx(0, RADIO_CLASS, tmp,
                          groupStyle | RADIO_FLAGS,0,0,0,0,
                          the_handle, (HMENU)newId, wxhInstance, NULL);
#if CTL3D
    Ctl3dSubclassCtl(radioButtons[i]);
#endif
#endif
    HDC the_dc = GetWindowDC((HWND)radioButtons[i]) ;
    if (buttonFont && buttonFont->GetInternalFont(the_dc))
      SendMessage((HWND)radioButtons[i],WM_SETFONT,
                  (WPARAM)buttonFont->GetInternalFont(the_dc),0L);
    ReleaseDC((HWND)radioButtons[i],the_dc) ;
    subControls.Append((wxObject *)newId);
  }
//  (void)NewId() ;
  // Create a dummy radio control to end the group.
  (void)CreateWindowEx(0, RADIO_CLASS, "", WS_GROUP|RADIO_FLAGS, 0,0,0,0, the_handle, (HMENU)NewId(), wxhInstance, NULL);

  no_items = N;
  SetSelection(0);

  SetSize(x, y, width, height);
  panel->AdvanceCursor(this);
  Callback(func);

  if (Title)
  {
    if (style&wxFIXED_LENGTH)
      SetLabel(Title) ;
  }
  if (the_label)
    delete [] the_label ;

  return TRUE;
}
#endif

wxRadioBox::~wxRadioBox(void)
{
  isBeingDeleted = TRUE;
  
  if (static_label)
    DestroyWindow(static_label);
  static_label = NULL;
  if (radioButtons)
  {
    for (int i = 0; i < no_items; i++)
      DestroyWindow(radioButtons[i]);
    delete[] radioButtons;
  }
  if (radioWidth)
    delete[] radioWidth ;
  if (radioHeight)
    delete[] radioHeight ;
  if (ms_handle)
    DestroyWindow(ms_handle) ;
  ms_handle = NULL ;

}

void wxRadioBox::SetBackgroundColour(wxColour*col)
{
}

void wxRadioBox::SetLabelColour(wxColour*col) 
{
}

void wxRadioBox::SetButtonColour(wxColour*col)
{
}

char *wxRadioBox::GetLabel(int item)
{
  char buf[300];
  GetWindowText((HWND)radioButtons[item], buf, 300);
  return copystring(buf);
}

void wxRadioBox::SetLabel(int item,char *label)
{
#if FAFA_LIB && !CTL3D
    // This message will switch from FB_BITMAP style to FB_TEXT, if needed.
    SendMessage((HWND)radioButtons[item],WM_CHANGEBITMAP,
                (WPARAM)0,
                (LPARAM)NULL);
#endif
  radioWidth[item] = radioHeight[item] = -1 ;
  SetWindowText((HWND)radioButtons[item], label);
}

void wxRadioBox::SetLabel(int item,wxBitmap *bitmap)
{
#if FAFA_LIB && !CTL3D
    SendMessage((HWND)radioButtons[item],WM_CHANGEBITMAP,
                (WPARAM)((bitmap->GetHeight()<<8)+bitmap->GetWidth()),
                (LPARAM)bitmap->ms_bitmap);
    radioWidth[item] = bitmap->GetWidth() + FB_MARGIN ;
    radioHeight[item] = bitmap->GetHeight() + FB_MARGIN ;
#endif
}

int wxRadioBox::FindString(char *s)
{
 for (int i = 0; i < no_items; i++)
 {
  GetWindowText(radioButtons[i], wxBuffer, 1000);
  if (strcmp(wxBuffer, s) == 0)
    return i;
 }
 return -1;
}

void wxRadioBox::SetSelection(int N)
{
  if ((N < 0) || (N >= no_items))
    return;

// Following necessary for Win32s, because Win32s translate BM_SETCHECK
#if FAFA_LIB
  if (selected >= 0 && selected < no_items)
    SendMessage(radioButtons[selected], isFafa?FAFA_SETCHECK:BM_SETCHECK, 0, 0L);
    
  SendMessage(radioButtons[N], isFafa?FAFA_SETCHECK:BM_SETCHECK, 1, 0L);
#else
  if (selected >= 0 && selected < no_items)
    SendMessage(radioButtons[selected], BM_SETCHECK, 0, 0L);
  
  SendMessage(radioButtons[N], BM_SETCHECK, 1, 0L);
#endif
  selected = N;
}

// Get single selection, for single choice list items
int wxRadioBox::GetSelection(void)
{
  return selected;
}

// Find string for position
char *wxRadioBox::GetString(int N)
{
  GetWindowText(radioButtons[N], wxBuffer, 1000);
  return wxBuffer;
}

void wxRadioBox::SetSize(int x, int y, int width, int height, int sizeFlags)
{
  int currentX, currentY;
  GetPosition(&currentX, &currentY);
  if (x == -1)
    x = currentX;
  if (y == -1)
    y = currentY;

  char buf[400];

  int y_offset = y;
  int x_offset = x;
  float current_width;

  float cyf;
  HWND wnd = (HWND)ms_handle;

  int cx1,cy1 ;
  wxGetCharSize(wnd, &cx1, &cy1,buttonFont);
  // Attempt to have a look coherent with other platforms:
  // We compute the biggest toggle dim, then we align all
  // items according this value.
  int maxWidth =  -1;
  int maxHeight = -1 ;

  for (int i = 0 ; i < no_items; i++)
  {
    int eachWidth;
    int eachHeight ;
    if (radioWidth[i]<0)
    {
      // It's a labelled toggle
      GetWindowText(radioButtons[i], buf, 300);
      GetTextExtent(buf, &current_width, &cyf,NULL,NULL, buttonFont);
      eachWidth = (int)(current_width + RADIO_SIZE);
      eachHeight = (int)((3*cyf)/2);
    }
    else
    {
      eachWidth = radioWidth[i] ;
      eachHeight = radioHeight[i] ;
    }
    if (maxWidth<eachWidth) maxWidth = eachWidth ;
    if (maxHeight<eachHeight) maxHeight = eachHeight ;
  }

  if (ms_handle)
  {
    int totWidth ;
    int totHeight;

    int nbHor,nbVer;

    if (labelPosition==wxVERTICAL)
    {
      nbVer = majorDim ;
      nbHor = (no_items+majorDim-1)/majorDim ;
    }
    else
    {
      nbHor = majorDim ;
      nbVer = (no_items+majorDim-1)/majorDim ;
    }

    // this formula works, but I don't know why.
    // Please, be sure what you do if you modify it!!
    if (radioWidth[0]<0)
      totHeight = (nbVer * maxHeight) + cy1/2 ;
    else
      totHeight = nbVer * (maxHeight+cy1/2) ;
    totWidth  = nbHor * (maxWidth+cx1) ;

#if (!CTL3D)
    // Requires a bigger group box in plain Windows
    MoveWindow(ms_handle,x_offset,y_offset,totWidth+cx1,totHeight+(3*cy1)/2,TRUE) ;
#else
    MoveWindow(ms_handle,x_offset,y_offset,totWidth+cx1,totHeight+cy1,TRUE) ;
#endif
    x_offset += cx1;
    y_offset += cy1;
  }

#if (!CTL3D)
  y_offset += (int)(cy1/2); // Fudge factor since buttons overlapped label
                            // JACS 2/12/93. CTL3D draws group label quite high.
#endif
  int startX = x_offset ;
  int startY = y_offset ;

  for ( i = 0 ; i < no_items; i++)
  {
    // Bidimensional radio adjustment
    if (i&&((i%majorDim)==0)) // Why is this omitted for i = 0?
    {
      if (labelPosition==wxVERTICAL)
      {
        y_offset = startY;
        x_offset += maxWidth + cx1 ;
      }
      else
      {
        x_offset = startX ;
        y_offset += maxHeight ;
        if (radioWidth[0]>0)
          y_offset += cy1/2 ;
      }
    }
    int eachWidth ;
    int eachHeight ;
    if (radioWidth[i]<0)
    {
      // It's a labeled item
      GetWindowText(radioButtons[i], buf, 300);
      GetTextExtent(buf, &current_width, &cyf,NULL,NULL,buttonFont);

      // How do we find out radio button bitmap size!!
      // By adjusting them carefully, manually :-)
      eachWidth = (int)(current_width + RADIO_SIZE);
      eachHeight = (int)((3*cyf)/2);
    }
    else
    {
      eachWidth = radioWidth[i] ;
      eachHeight = radioHeight[i] ;
    }

    MoveWindow(radioButtons[i],x_offset,y_offset,eachWidth,eachHeight,TRUE);
    if (labelPosition == wxVERTICAL)
    {
      y_offset += maxHeight;
      if (radioWidth[0]>0)
        y_offset += cy1/2 ;
    }
    else
      x_offset += maxWidth + cx1;
  }
  GetEventHandler()->OnSize(width, height);
}

void wxRadioBox::GetSize(int *width, int *height)
{
  RECT rect;
  rect.left = -1; rect.right = -1; rect.top = -1; rect.bottom = -1;

  if (static_label)
    wxFindMaxSize(static_label, &rect);

  if (ms_handle)
    wxFindMaxSize(ms_handle, &rect);

  for (int i = 0; i < no_items; i++)
    wxFindMaxSize(radioButtons[i], &rect);

  *width = rect.right - rect.left;
  *height = rect.bottom - rect.top;
}

void wxRadioBox::GetPosition(int *x, int *y)
{
  wxWindow *parent = GetParent();
  RECT rect;
  rect.left = -1; rect.right = -1; rect.top = -1; rect.bottom = -1;

  for (int i = 0; i < no_items; i++)
    wxFindMaxSize(radioButtons[i], &rect);

  if (static_label)
    wxFindMaxSize(static_label, &rect);

  if (ms_handle)
    wxFindMaxSize(ms_handle, &rect);

  // Since we now have the absolute screen coords,
  // if there's a parent we must subtract its top left corner
  POINT point;
  point.x = rect.left;
  point.y = rect.top;
  if (parent)
  {
    wxWnd *cparent = (wxWnd *)(parent->handle);
    ::ScreenToClient(cparent->handle, &point);
  }

  *x = point.x;
  *y = point.y;
}

char *wxRadioBox::GetLabel(void)
{
  if (static_label)
  {
    GetWindowText(static_label, wxBuffer, 300);
    return wxBuffer;
  }
  else return NULL;
}

void wxRadioBox::SetLabel(char *label)
{
  if (static_label)
  {
    float w, h;
    RECT rect;

    wxWindow *parent = GetParent();
    GetWindowRect(static_label, &rect);

    // Since we now have the absolute screen coords,
    // if there's a parent we must subtract its top left corner
    POINT point;
    point.x = rect.left;
    point.y = rect.top;
    if (parent)
    {
      wxWnd *cparent = (wxWnd *)(parent->handle);
      ::ScreenToClient(cparent->handle, &point);
    }

    GetTextExtent((LPSTR)label, &w, &h, NULL, NULL,labelFont);
    MoveWindow(static_label, point.x, point.y, (int)(w + 10), (int)h,
               TRUE);
    SetWindowText(static_label, label);
  }
}

void wxRadioBox::SetFocus(void)
{
  if (no_items > 0)
   ::SetFocus(radioButtons[0]);
}

Bool wxRadioBox::Show(Bool show)
{
  int cshow;
  if (show)
    cshow = SW_SHOW;
  else
    cshow = SW_HIDE;
  if (static_label)
    ShowWindow(static_label, cshow);
  for (int i = 0; i < no_items; i++)
    ShowWindow(radioButtons[i], cshow);
  return TRUE;
}

// Enable a specific button
void wxRadioBox::Enable(int item, Bool enable)
{
  if (item<0)
    wxWindow::Enable(enable) ;
  else if (item < no_items)
    ::EnableWindow(radioButtons[item], enable);
}

// Show a specific button
void wxRadioBox::Show(int item, Bool show)
{
  if (item<0)
    wxRadioBox::Show(show) ;
  else if (item < no_items)
  {
    int cshow;
    if (show)
      cshow = SW_SHOW;
    else
      cshow = SW_HIDE;
    ShowWindow(radioButtons[item], cshow);
  }
}
