#include "wxinc.h"

#include "xvt.h"
#include "xvtart.h"
#include "oswin32.h"

#include <wx/artprov.h>
#include <wx/aui/aui.h>
#include <wx/filename.h>

wxString xvtart_GetResourceIni()
{ 
  DIRECTORY dir; xvt_fsys_get_default_dir(&dir);
  wxString str = dir.path;
  str += "/res/resource.ini";
  return str; 
}

wxString xvtart_GetResourceName(const char* type, int rid)
{
	wxString strName(type); strName << "s";
  wxString strKey; strKey.Printf("%d", rid);

  DIRECTORY dir; xvt_fsys_get_default_dir(&dir);
  wxString startup_dir = dir.path;

  if ((rid == ICON_RSRC || rid == 0) && strName == "Icons")
  {
    int i = 1;
    switch (xvt_sys_get_os_version())
    {
    case XVT_WS_WIN_2000:
    case XVT_WS_WIN_2003: i = 0; break; // Cerco prima l'icona a 256 colori
    default             : i = 1; break; // Cerco solo l'icona in RGBA
    }
    for (; i < 2; i++)
    {
      const char* const oem_var = i == 0 ? "Icon256" : "Icon";
      char name[MAX_PATH];
      if (xvt_sys_get_oem_string(oem_var, "", name, sizeof(name)))
      {
        wxFileName fname(startup_dir + "/setup/" + name);
        if (fname.FileExists())
        {
          fname.Normalize();
          strName = fname.GetFullPath().Lower();
          return strName;
        }
      }
    }
  }

  wxString val;
  char* buff = val.GetWriteBuf(MAX_PATH);
  xvt_sys_get_profile_string(xvtart_GetResourceIni(), strName, strKey, "", buff, MAX_PATH);
  val.UngetWriteBuf();

	if (!val.IsEmpty())
	{
		strName = startup_dir;
		strName += "/custom/";
		strName += val;

    if (!wxFileExists(strName))
    {
      strName = startup_dir;
		  strName += "/res/";
		  strName += val;
    }

    wxFileName fname(strName);
    fname.Normalize();
    strName = fname.GetFullPath().Lower();
	}
	else
		strName.Empty();
	 
  return strName;
}

///////////////////////////////////////////////////////////
// TArtProvider
///////////////////////////////////////////////////////////

class TArtProvider : public wxArtProvider
{
#if !wxCHECK_VERSION(2,9,0)
  WX_DECLARE_STRING_HASH_MAP(wxIconBundle, TIconBundleHashTable);
  TIconBundleHashTable m_hmBundles;

  WX_DECLARE_STRING_HASH_MAP(unsigned, TIconIdHashTable);
  TIconIdHashTable m_hmIds;
#endif

protected:
  virtual wxBitmap CreateBitmap(const wxArtID& id, const wxArtClient& client, const wxSize& size);
  virtual wxIconBundle CreateIconBundle(const wxArtID& id, const wxArtClient& client);

public:
#if !wxCHECK_VERSION(2,9,0)
  wxIconBundle GetIconBundle(const wxArtID& id, const wxArtClient& client);
  wxIcon GetIcon(const wxArtID& id, const wxArtClient& client = wxART_OTHER, const wxSize& size = wxDefaultSize);
  wxSize GetNativeSizeHint(const wxArtClient& client);
#endif
  unsigned int GetIconBundleNumber(const wxArtID& id);
};

TArtProvider* _TheArtProvider = NULL;

void xvtart_Init()
{
  if (_TheArtProvider == NULL)
    _TheArtProvider = new TArtProvider;
  wxArtProvider::Push(_TheArtProvider);
}

wxBitmap TArtProvider::CreateBitmap(const wxArtID& id, const wxArtClient& client, const wxSize& size)
{
  wxString strName;

  long tool = -1;
  if (id.StartsWith(wxT("wxART")))
  {
    if (id == wxART_ERROR)         tool = 201; else
    if (id == wxART_HELP)          tool = 163; else
    if (id == wxART_INFORMATION)   tool = 162; else
    if (id == wxART_MISSING_IMAGE) tool = 100; else
    if (id == wxART_NEW)           tool = 105; else
    if (id == wxART_QUESTION)      tool = 202; else
    if (id == wxART_QUIT)          tool = 114; else 
    if (id == wxART_WARNING)       tool = 203; else
    ;
  }
  else
    id.ToLong(&tool);

  if (tool > 0)
  {
    strName = xvtart_GetResourceName("Tool", tool);
    if (strName.IsEmpty() || !::wxFileExists(strName))
      strName = xvtart_GetResourceName("Tool", 100); // Default empty icon
  }
  else
    strName = id;

  if (!strName.IsEmpty() && ::wxFileExists(strName))
  {
    if (strName.EndsWith(".ico"))
    {
      const wxIcon ico = GetIcon(strName, client, size);
      return wxBitmap(ico);
    } 
    else
    {
      int sx = size.x, sy = size.y;
      if (sx <= 0 || sy <= 0)
      {
        const wxSize sz = GetNativeSizeHint(client);
        if (sx <= 0) sx = sz.x;
        if (sy <= 0) sy = sz.y;
      }
      wxImage img(strName, wxBITMAP_TYPE_ANY);
      img.Rescale(sx, sy, wxIMAGE_QUALITY_HIGH);
      return wxBitmap(img);
    }
  }

  return wxNullBitmap;
}

wxIconBundle TArtProvider::CreateIconBundle(const wxArtID& id, const wxArtClient& WXUNUSED(client))
{
  wxString strName = id;

  long nIco = -1;
  if (id.StartsWith(wxT("wxART")))
  {
    if (id == wxART_EXECUTABLE_FILE) nIco = ICON_RSRC; else
    ;
  }
  else
    id.ToLong(&nIco);

  if (nIco > 0)
    strName = xvtart_GetResourceName("Icon", nIco);

  wxIconBundle ib;
  bool bFound = false;
  if (::wxFileExists(strName))
  {
    const bool bLog = wxLog::EnableLogging(false); // Evita segnalazione di errore di formato icona
    if (strName.EndsWith(wxT(".ico")))
    {
      ib.AddIcon(strName, wxBITMAP_TYPE_ICO);
      bFound = true;
    }
    else
    {
      ib.AddIcon(OsWin32_LoadIcon(strName));
      bFound = true;
    }
    wxLog::EnableLogging(bLog);

    for (wxCoord s = 16; s <= 48; s += 16)
    {
      const wxIcon smico = ib.GetIcon(s);
      if (smico.GetWidth() != s)
      {
        wxBitmap bmpbig(ib.GetIcon());
        wxImage img = bmpbig.ConvertToImage();
        img.Rescale(s, s, wxIMAGE_QUALITY_HIGH);
        wxBitmap bmpsmall(img);
        wxIcon icosmall; icosmall.CopyFromBitmap(bmpsmall);
        ib.AddIcon(icosmall);
      }
    }
  }
  else
  {
    if (!strName.IsEmpty()) // Getione caso strName=".ext"
    {
      ib.AddIcon(OsWin32_LoadIcon(strName));
      bFound = true;
    }
  }

  if (!bFound && nIco == ICON_RSRC)
  {
    strName.Printf("%d", ICON_RSRC); // id puo' essere wxART_EXECUTABLE_FILE
    ib.AddIcon(wxIcon(strName, wxBITMAP_TYPE_ICO_RESOURCE));
  }

  return ib;
}

#if !wxCHECK_VERSION(2,9,0)

wxSize TArtProvider::GetNativeSizeHint(const wxArtClient& client)
{
  int ix = 32, iy = 32;
  
  if (client == wxART_FRAME_ICON)
  {
    const int x = wxSystemSettings::GetMetric(wxSYS_SMALLICON_X);
    const int y = wxSystemSettings::GetMetric(wxSYS_SMALLICON_Y);
    if (x > 0 && y > 0)
    { ix = x; iy = y; }
    else
    { ix /= 2; iy /= 2; }
  }
  else
  {
    const int x = wxSystemSettings::GetMetric(wxSYS_ICON_X);
    const int y = wxSystemSettings::GetMetric(wxSYS_ICON_Y);
    if (x > 0 && y > 0)
    { ix = x; iy = y; }
    if (client == wxART_MESSAGE_BOX)
    { ix *= 2; iy *= 2; }
  }
  
  return wxSize(ix,iy);
}

wxIconBundle TArtProvider::GetIconBundle(const wxArtID& id, const wxArtClient& client)
{
  TIconBundleHashTable::iterator it = m_hmBundles.find(id);
  if (it == m_hmBundles.end())
  {
    const wxIconBundle b = CreateIconBundle(id, client);
    m_hmBundles[id] = b;

    unsigned long uid = 0;
    if (!id.ToULong(&uid))
    {
      wxString numid; numid.Printf(wxT("%lu"), GetIconBundleNumber(id));
      m_hmBundles[numid] = b;
    }

    return b;
  }
  return it->second;
}

wxIcon TArtProvider::GetIcon(const wxArtID& id, const wxArtClient& client, const wxSize& size)
{
  wxIconBundle bundle = GetIconBundle(id, client);
  const wxSize sz = size == wxDefaultSize ? GetNativeSizeHint(client) : size;
  wxIcon ico = bundle.GetIcon(sz);
  if (ico.IsOk() && sz.x != ico.GetWidth()) // Should never happen :-)
  {
    wxBitmap bmpbig(bundle.GetIcon());
    wxImage img = bmpbig.ConvertToImage();
    img.Rescale(sz.x, sz.y, wxIMAGE_QUALITY_HIGH);
    wxBitmap bmpsmall(img);
    wxIcon icosmall; icosmall.CopyFromBitmap(bmpsmall);
    ico = icosmall;
    bundle.AddIcon(ico);
  }
  return ico;  
}

// Metodo fichissimo per assegnare un identificatore univoco alle icone chiamate per nome del file.*
unsigned int TArtProvider::GetIconBundleNumber(const wxArtID& id)
{
  unsigned int num = m_hmIds[id];
  if (num == 0)
  {
    num = 60000+m_hmIds.size();
    m_hmIds[id] = num;
  }
  return num;
}

#endif

///////////////////////////////////////////////////////////
// xvt_sys_load_icon
///////////////////////////////////////////////////////////

const wxBitmap xvtart_GetToolResource(int nIcon, int nDesiredSize)
{
  if (nDesiredSize < 16) nDesiredSize = 16; else
  if (nDesiredSize > 128) nDesiredSize = 128;
  wxArtID id; id.Printf("%d", nIcon);
  return wxArtProvider::GetBitmap(id, wxART_TOOLBAR, wxSize(nDesiredSize, nDesiredSize));
}

const wxIcon xvtart_GetIconResource(int nIcon, const char* client, const int size)
{
  wxASSERT(_TheArtProvider != NULL);

  if (nIcon <= 0) 
    nIcon = ICON_RSRC;

  wxArtID id; id.Printf("%d", nIcon);
  wxArtClient cl = client && * client ? client : wxART_OTHER;
  wxSize sz(size, size);
  return _TheArtProvider->GetIcon(id, cl, sz);
}

unsigned int xvt_sys_load_icon(const char* file)
{
  wxASSERT(_TheArtProvider != NULL);
  const wxArtID id = file;
  const wxIcon ico = _TheArtProvider->GetIcon(id);
  return ico.IsOk() ? _TheArtProvider->GetIconBundleNumber(id) : ICON_RSRC;
}

WX_DECLARE_HASH_MAP(int, wxCursor, wxIntegerHash, wxIntegerEqual, TCursorHashTable);

const wxCursor xvtart_GetCursorResource(int rid)
{
	static TCursorHashTable _nice_cursors;
  wxCursor cursor = _nice_cursors[rid];
  
  if (!cursor.IsOk())
	{
		switch (rid)
		{
    case CURSOR_CROCE: cursor = wxCURSOR_CROSS;	break;
		case CURSOR_IBEAM: cursor = wxCURSOR_IBEAM;	break;
		default:
			{
				const wxString strName = xvtart_GetResourceName("Cursor", rid);
				if (::wxFileExists(strName))
				{
          if (strName.Find(".ico") > 0)
            cursor = wxCursor(strName, wxBITMAP_TYPE_ICO);
          else
					  cursor = wxCursor(strName, wxBITMAP_TYPE_CUR);
				}
			}
			break;
		}
		if (!cursor.IsOk())
		{
    	wxFAIL_MSG(_("Invalid cursor"));
			cursor = *wxSTANDARD_CURSOR;
		}
		
    _nice_cursors[rid] = cursor;
	}
	return cursor;
}

///////////////////////////////////////////////////////////
// TAuiManager
///////////////////////////////////////////////////////////

/*
class TAuiManager : public wxAuiManager
{
public:
  static bool DrawBackground(wxDC& dc, wxWindow* window, int orientation, const wxRect &rect);
  static bool BaseColours(wxColour& base, wxColour& light, wxColour& dark, wxColour& text);
  TAuiManager();
};

bool TAuiManager::BaseColours(wxColour& base, wxColour& light, wxColour& dark, wxColour& text)
{
  const wxSize sz(256,256);
  wxBitmap bmp = wxArtProvider::GetBitmap(wxArtID(wxT("Skin")), wxART_OTHER, sz);
  if (bmp.IsOk())
  {
    wxColourBase::ChannelType ldark = 255, llight = 0;
    dark = *wxWHITE;
    light = *wxBLACK;

    wxNativePixelData data(bmp);
    const int dim = data.GetHeight();
    wxNativePixelData::Iterator p(data);
    double r = 0, g = 0, b = 0;
    for (int i = 0; i < dim; i++)
    {
      p.MoveTo(data, i, i);
      r += p.Red();
      g += p.Green();
      b += p.Blue();

      const wxColour col(p.Red(), p.Green(), p.Blue());
      const wxColourBase::ChannelType lcol = Luma(col);
      if (lcol < ldark)
      {
        dark = col;
        ldark = lcol;
      }
      if (lcol > llight)
      {
        light = col;
        llight = lcol;
      }
    }
    r /= dim; g /= dim; b /= dim;

    base = wxColour(r, g, b);
    const wxColourBase::ChannelType lbase = Luma(base);
    if (lbase - ldark < 40)
      dark = ModulatedColor(dark, -(40 - lbase + ldark));

    if (llight - lbase < 40)
      light = ModulatedColor(light, +(40 - llight + lbase));

    text = ContrastingColor(base);
  }
  return bmp.IsOk();
}

bool TAuiManager::DrawBackground(wxDC& dc, wxWindow* WXUNUSED(window), 
                                  int WXUNUSED(orientation), const wxRect &rect)
{
  const wxBitmap bmp = wxArtProvider::GetBitmap(wxArtID(wxT("Skin")), wxART_OTHER, wxSize(256,256));
  if (bmp.IsOk())
  {
    const wxSize szBm = bmp.GetSize();
    for (wxCoord y = rect.y; y < rect.GetBottom(); y += szBm.y)
    {
      for (wxCoord x = rect.x; x < rect.GetRight(); x += szBm.x)
        dc.DrawBitmap(bmp, x, y);
    }
  }
  return bmp.IsOk();
}
  
TAuiManager::TAuiManager()
{
  SetArtProvider(new TDockArt);
}
*/

wxAuiManager* xvtart_CreateManager(wxWindow* win)
{
  return new wxAuiManager(win); // will be TAUIManager
}