#include "wxinc.h"

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

#ifdef __WXMSW__
#include "oswin32.h"
#endif

#include <wx/artprov.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;
    }
#ifdef __WXMSW__
    else
    {
      ib.AddIcon(OsWin32_LoadIcon(strName));
      bFound = true;
    }
#endif
    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);
      }
    }
  }
#ifdef __WXMSW__
  else
  {
    if (!strName.IsEmpty()) // Getione caso strName=".ext"
    {
      ib.AddIcon(OsWin32_LoadIcon(strName));
      bFound = true;
    }
  }
#endif

  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;
  _TheArtProvider->GetIcon(id);
  return _TheArtProvider->GetIconBundleNumber(id);
}

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;
}