/******************************************************************************
 *
 * Copyright (C) 1997-2015 by Dimitri van Heesch.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation under the terms of the GNU General Public License is hereby
 * granted. No representations are made about the suitability of this software
 * for any purpose. It is provided "as is" without express or implied warranty.
 * See the GNU General Public License for more details.
 *
 * Documents produced by Doxygen are derivative works derived from the
 * input used in their production; they are not affected by this license.
 *
 */
#include <qdict.h>
#include <qfile.h>
#include <qcstring.h>
#include <qglobal.h>
#include <string.h>

#include "resourcemgr.h"
#include "util.h"
#include "version.h"
#include "ftextstream.h"
#include "message.h"
#include "config.h"

class ResourceMgr::Private
{
  public:
    Private() : resources(257) {}
    QDict<Resource> resources;
};

ResourceMgr &ResourceMgr::instance()
{
  static ResourceMgr theInstance;
  return theInstance;
}

ResourceMgr::ResourceMgr()
{
  p = new Private;
}

ResourceMgr::~ResourceMgr()
{
  delete p;
}

void ResourceMgr::registerResources(const Resource resources[],int numResources)
{
  for (int i=0;i<numResources;i++)
  {
    p->resources.insert(resources[i].name,&resources[i]);
  }
}

bool ResourceMgr::writeCategory(const char *categoryName,const char *targetDir) const
{
  QDictIterator<Resource> it(p->resources);
  const Resource *res;
  for (it.toFirst();(res=it.current());++it)
  {
    if (qstrcmp(res->category,categoryName)==0)
    {
      QCString pathName = QCString(targetDir)+"/"+res->name;
      QFile f(pathName);
      if (!f.open(IO_WriteOnly) || f.writeBlock((const char *)res->data,res->size)!=res->size)
      {
        err("Failed to write resource '%s' to directory '%s'\n",res->name,targetDir);
        return FALSE;
      }
    }
  }
  return TRUE;
}

bool ResourceMgr::copyResourceAs(const char *name,const char *targetDir,const char *targetName) const
{
  QCString pathName = QCString(targetDir)+"/"+targetName;
  const Resource *res = get(name);
  if (res)
  {
    switch (res->type)
    {
      case Resource::Verbatim:
        {
          QFile f(pathName);
          if (f.open(IO_WriteOnly) && f.writeBlock((const char *)res->data,res->size)==res->size)
          {
            return TRUE;
          }
        }
        break;
      case Resource::Luminance:
        {
          QCString n = name;
          n = n.left(n.length()-4)+".png"; // replace .lum by .png
          uchar *p = (uchar*)res->data;
          int width   = (p[0]<<8)+p[1];
          int height  = (p[2]<<8)+p[3];
          ColoredImgDataItem images[2];
          images[0].name    = n;
          images[0].width   = width;
          images[0].height  = height;
          images[0].content = &p[4];
          images[0].alpha   = 0;
          images[1].name    = 0; // terminator
          writeColoredImgData(targetDir,images);
          return TRUE;
        }
        break;
      case Resource::LumAlpha:
        {
          QCString n = name;
          n = n.left(n.length()-5)+".png"; // replace .luma by .png
          uchar *p = (uchar*)res->data;
          int width   = (p[0]<<8)+p[1];
          int height  = (p[2]<<8)+p[3];
          ColoredImgDataItem images[2];
          images[0].name    = n;
          images[0].width   = width;
          images[0].height  = height;
          images[0].content = &p[4];
          images[0].alpha   = &p[4+width*height];
          images[1].name    = 0; // terminator
          writeColoredImgData(targetDir,images);
          return TRUE;
        }
        break;
      case Resource::CSS:
        {
          QFile f(pathName);
          if (f.open(IO_WriteOnly))
          {
            QCString buf(res->size+1);
            memcpy(buf.rawData(),res->data,res->size);
            FTextStream t(&f);
            buf = replaceColorMarkers(buf);
            if (qstrcmp(name,"navtree.css")==0)
            {
              t << substitute(buf,"$width",QCString().setNum(Config_getInt(TREEVIEW_WIDTH))+"px");
            }
            else
            {
              t << substitute(buf,"$doxygenversion",versionString);
            }
            return TRUE;
          }
        }
        break;
    }
  }
  else
  {
    err("requested resource '%s' not compiled in!\n",name);
  }
  return FALSE;
}

bool ResourceMgr::copyResource(const char *name,const char *targetDir) const
{
  return copyResourceAs(name,targetDir,name);
}

const Resource *ResourceMgr::get(const char *name) const
{
  return p->resources.find(name);
}

QCString ResourceMgr::getAsString(const char *name) const
{
  const Resource *res = get(name);
  if (res)
  {
    QCString result(res->size+1);
    memcpy(result.rawData(),res->data,res->size);
    return result;
  }
  else
  {
    return QCString();
  }
}

