// This file is part of the aMule Project
//
// Copyright (c) 2003-2004 aMule Project ( http://www.amule-project.net )
// Copyright (C) 2002 Merkur ( merkur-@users.sourceforge.net / http://www.emule-project.net )
//
// 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; either
// version 2 of the License, or (at your option) any later version.
// 
// 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//

#include "sys.h"
#include <gtk/gtk.h>
#include <wx/wx.h> 		// BSD needs it
#include "TabCtrl.h"		// Interface declarations.

DEFINE_EVENT_TYPE(wxEVT_TAB_CHANGED)

BEGIN_EVENT_TABLE(wxTabCtrl,wxControl)
  EVT_LEFT_DOWN(wxTabCtrl::OnLeftDown)
  EVT_MOTION(wxTabCtrl::OnMotion)
END_EVENT_TABLE()

  //  EVT_PAINT(wxTabCtrl::OnPaint)

// internal class
class TabItem {
public:
  TabItem() { width=-1; };
  wxString getTitle() { return mTitle; };
  void setTitle(wxString title) {mTitle=title;};
  long getUserData() { return mUserData; };
  void setUserData(long userData) {mUserData=userData;};
  int getWidth() {return width;};
  void setWidth(int newWidth) {width=newWidth;};
private:
  wxString mTitle;
  long mUserData;
  int width;
};

#include <wx/listimpl.cpp>
#include <wx/defs.h>		// Needed before any other wx/*.h
#include <wx/defs.h>		// Needed for GtkWidget
WX_DEFINE_LIST(TabList);

IMPLEMENT_DYNAMIC_CLASS(wxTabCtrl,wxControl)

GtkWidget* tmpwid=NULL;

gboolean expose_evt(GtkWidget* widget,GdkEventExpose* evt,gpointer data)
{
  wxTabCtrl* _this=(wxTabCtrl*)data;
  _this->OnPaint(widget,evt);
  return TRUE;
}

bool wxTabCtrl::Create(wxWindow* parent,
		       const wxWindowID id,const wxPoint& pos,
		       const wxSize& size,const long int style)
{
  // create base window
  //if(!wxWindow::Create(parent,id,pos,size,0))
  //  return FALSE;

  if(!PreCreation(parent,pos,size) ||
     !CreateBase(parent,id,pos,size,style)) {
    printf("Error.\n");
    return FALSE;
  }

  m_widget=gtk_drawing_area_new();

  // we need the notebook's style..
  tmpwid=gtk_notebook_new();
  GtkStyle* newstyle=gtk_rc_get_style(tmpwid);
  if(!newstyle) newstyle=gtk_widget_get_default_style();
  newstyle=gtk_style_copy(newstyle);
  gtk_style_ref(newstyle);
  gtk_widget_set_style(m_widget,newstyle);

  gtk_signal_connect(GTK_OBJECT(m_widget),"expose_event",GTK_SIGNAL_FUNC(expose_evt),this);
  gtk_widget_destroy(tmpwid);

  m_parent->DoAddChild(this);
  PostCreation();
  SetBestSize(size);
  Show(TRUE);

  //SetBackgroundColour(GetColour(wxSYS_COLOUR_WINDOW));
  m_tabs.Clear();
  currentTab=0;
  firstTab=0;
  prelightRight=false;
  prelightLeft=false;

  Refresh();

  return TRUE;	// Success.
}

int wxTabCtrl::calcTabWidth() {
  int width=0;
  TabList::Node* n=m_tabs.GetFirst();
  while(n) {
    TabItem* ni=n->GetData();
    width+=ni->getWidth();
    n=n->GetNext();
  }
  return width;
}

long wxTabCtrl::InsertItem(int nMask,int nItem,wxString title,int nImage,long lpar)
{
  TabItem* ni=new TabItem();
  ni->setTitle(title);
  ni->setUserData(lpar);
  ni->setWidth(-1); // ensure resize at first paint
  m_tabs.Insert(nItem,ni);
  return m_tabs.IndexOf(ni);
}

void wxTabCtrl::OnMotion(wxMouseEvent& evt)
{
  wxRect myrcx=GetRect();

  if(myrcx.width/calcTabWidth()>(int)m_tabs.GetCount())
    return;
  bool oldRight=prelightRight;
  bool oldLeft=prelightLeft;
  if(evt.GetX()>myrcx.width-11) {
    prelightRight=true;
  } else {
    prelightRight=false;
  }
  if(evt.GetX()>myrcx.width-21 && evt.GetX()<myrcx.width-11) {
    prelightLeft=true;
  } else {
    prelightLeft=false;
  }
  if((oldRight!=prelightRight)||(oldLeft!=prelightLeft)) {
    Refresh(FALSE);
  }
}

int wxTabCtrl::tabsVisible()
{ 
  wxRect myrcx=GetRect();
  if(myrcx.width/calcTabWidth()>(int)m_tabs.GetCount())
    return m_tabs.GetCount();
  return (myrcx.width/calcTabWidth());
}

void wxTabCtrl::OnLeftDown(wxMouseEvent& evt)
{
  if((int)m_tabs.GetCount()>tabsVisible()) {
    wxRect rc=GetRect();
    if(evt.GetX()>rc.width-11) {
      // skroll
      if(firstTab+tabsVisible()<(int)m_tabs.GetCount()) {
	firstTab++;
	Refresh(FALSE);
      }
      return;
    }
    if(evt.GetX()>rc.width-21) {
      // skroll
      if(firstTab>0) {
	firstTab--;
	Refresh(FALSE);
      }
      return;
    }
  }

  int newTab=(evt.GetX()/100); // hmm..

  if(newTab>tabsVisible()-1)
    return;
  if(newTab<0) 
    return;

  currentTab=firstTab+newTab;

  Refresh(FALSE);

  // emit event
  wxCommandEvent ev(wxEVT_TAB_CHANGED,GetId());
  GetEventHandler()->ProcessEvent(ev);
}

void wxTabCtrl::OnPaint(GtkWidget* widget,GdkEventExpose* evt)
{
  wxRect myrcx=GetRect();
  printf("rc=%d %d %d %d\n",myrcx.x,myrcx.y,myrcx.width,myrcx.height);
  // get the style
  gtk_widget_reset_rc_styles(m_widget);
  GdkRectangle myrc={evt->area.x,evt->area.y,evt->area.width,evt->area.height};//myrcx.x,myrcx.y,myrcx.width,myrcx.height};

  // draw inactive tabs
  int ythickness;
#ifdef __GTK2__
  ythickness=m_widget->style->ythickness;
#else
  ythickness=widget->style->klass->ythickness;
#endif

  int xc=0;
  for(unsigned int i = firstTab; i < m_tabs.GetCount(); ++i) {
    TabItem* item=m_tabs.Item(i)->GetData();
    if(item->getWidth()==(-1)) {
      // need to recalculate the width
      int newwid=0;
#ifdef __GTK2__
      newwid=10; // ugly hack to ensure width > 0
#else
      newwid=gdk_string_width(widget->style->font,item->getTitle());
#endif
     item->setWidth(newwid);
    }

    if(xc+item->getWidth()>(myrcx.width-20)) break; // don't draw tabs outside the window 

    if(i!=(unsigned int)currentTab) {
      gtk_paint_flat_box(widget->style,widget->window,
			 GTK_STATE_NORMAL,GTK_SHADOW_NONE,
			 &myrc,widget,"tab",
			 xc,4,item->getWidth(),24+2*ythickness);
      gtk_paint_extension(widget->style,widget->window,
			  GTK_STATE_ACTIVE,GTK_SHADOW_OUT,
			  &myrc,widget,
			  "tab",xc,4+2*ythickness,item->getWidth(),24,GTK_POS_BOTTOM);
      gtk_paint_string(widget->style,widget->window,
		       GTK_STATE_NORMAL,
		       &myrc,widget,
		       "tab",xc+10,4+15+2*ythickness,item->getTitle());
    }
    xc+=item->getWidth();
  }

  // then draw active tab
  gtk_paint_extension(widget->style,widget->window,
		      GTK_STATE_NORMAL,GTK_SHADOW_OUT,
		      &myrc,widget,
		      "tab",(currentTab-firstTab)*100,4,100,24+2*ythickness,GTK_POS_BOTTOM);
  
  gtk_paint_string(widget->style,widget->window,
		   GTK_STATE_ACTIVE,
		   &myrc,widget,
		   "tab",(currentTab-firstTab)*100+10,4+15,
		   m_tabs.Item(currentTab)->GetData()->getTitle());

  // paint arrows only if necessary
  if(m_tabs.GetCount()>(unsigned int)tabsVisible()) {
    GtkStateType state=GTK_STATE_NORMAL;
    if(prelightLeft) state=GTK_STATE_INSENSITIVE;
    gtk_paint_arrow(widget->style,widget->window,
		    state,GTK_SHADOW_ETCHED_OUT,
		    &myrc,widget,
		    "notebook",GTK_ARROW_LEFT,TRUE,
		    myrcx.width-20,20,16,16);
    state=GTK_STATE_NORMAL;
    if(prelightRight) state=GTK_STATE_INSENSITIVE;
    gtk_paint_arrow(widget->style,widget->window,
		    state,GTK_SHADOW_ETCHED_OUT,
		    &myrc,widget,
		    "notebook",GTK_ARROW_RIGHT,TRUE,
		    myrcx.width-10,20,16,16);
  }
}
