/*
 * This file is part of the apvlv package
 * Copyright (C) <2008>  <Alf>
 *
 * Contact: Alf <naihe2010@126.com>
 *
 * 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.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */
/* @CPPFILE ApvlvFile.cc
 *
 *  Author: Alf <naihe2010@126.com>
 */
/* @date Created: 2009/11/20 19:38:30 Alf*/

#include "ApvlvFile.h"
#include "ApvlvEpub.h"
#include "ApvlvHtm.h"
#include "ApvlvPdf.h"
#include "ApvlvUtil.h"

#ifdef APVLV_WITH_DJVU
#include "ApvlvDjvu.h"
#endif
#ifdef APVLV_WITH_TXT
#include "ApvlvTxt.h"
#endif

#include <glib.h>
#include <iostream>
#include <sys/stat.h>
#include <utility>

namespace apvlv
{
#ifndef MAX
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif

ApvlvFile::ApvlvFile (__attribute__ ((unused)) const char *filename,
                      __attribute__ ((unused)) bool check)
{
  mIndex = nullptr;

  mRawdata = nullptr;
  mRawdataSize = 0;
}

ApvlvFile::~ApvlvFile ()
{
  delete[] mRawdata;
  mRawdata = nullptr;

  mPages.clear ();
  srcPages.clear ();
  srcMimeTypes.clear ();
}

ApvlvFile *
ApvlvFile::newFile (const char *filename, __attribute__ ((unused)) bool check)
{
  ApvlvFile *file;
  static const char *type_phrase[] = {
    ".pdf", ".html", ".htm", ".epub", ".djv", ".djvu", ".txt",
  };

  size_t i;
  for (i = 0; i < sizeof (type_phrase) / sizeof (type_phrase[0]); ++i)
    {
      if (strlen (filename) >= strlen (type_phrase[i])
          && strcasecmp (filename + strlen (filename)
                             - strlen (type_phrase[i]),
                         type_phrase[i])
                 == 0)
        {
          break;
        }
    }

  if (i == sizeof (type_phrase) / sizeof (type_phrase[0]))
    {
      debug ("not a valid file: %s, treate as a PDF file", filename);
      i = 0;
    }

  file = nullptr;
  try
    {
      switch (i)
        {
        case 0:
          file = new ApvlvPDF (filename);
          break;

        case 1:
        case 2:
          file = new ApvlvHTML (filename);
          break;

        case 3:
          file = new ApvlvEPUB (filename);
          break;

        case 4:
        case 5:
#ifdef APVLV_WITH_DJVU
          file = new ApvlvDJVU (filename);
#endif
          break;

        case 6:
#ifdef APVLV_WITH_TXT
          file = new ApvlvTXT (filename);
#endif
          break;

        default:;
        }
    }

  catch (const bad_alloc &e)
    {
      delete file;
      file = nullptr;
    }

  return file;
}

bool
ApvlvFile::render (int pn, int ix, int iy, double zm, int rot, GdkPixbuf *pix,
                   char *buffer)
{
  return false;
}

bool
ApvlvFile::renderweb (int pn, int, int, double, int, GtkWidget *widget)
{
  return false;
}

gchar *
ApvlvFile::get_ocf_file (const gchar *path, gssize *sizep)
{
  return nullptr;
}

const gchar *
ApvlvFile::get_ocf_mime_type (const gchar *path)
{
  if (srcMimeTypes.find (path) != srcMimeTypes.end ())
    return srcMimeTypes[path].c_str ();
  return "text/html";
}

int
ApvlvFile::get_ocf_page (const gchar *path)
{
  if (srcPages.find (path) != srcPages.end ())
    return srcPages[path];
  return -1;
}

bool
ApvlvFile::annot_underline (int, gdouble, gdouble, gdouble, gdouble)
{
  return false;
}

bool
ApvlvFile::annot_text (int, gdouble, gdouble, gdouble, gdouble,
                       const char *text)
{
  return false;
}

ApvlvAnnotTexts
ApvlvFile::getAnnotTexts (int pn)
{
  ApvlvAnnotTexts texts;
  return texts;
}
bool
ApvlvFile::annot_update (int, ApvlvAnnotText *text)
{
  return false;
}

ApvlvFileIndex *
ApvlvFileIndex::newDirIndex (const gchar *path, ApvlvFileIndex *parent_index)
{
  ApvlvFileIndex *root_index = parent_index;
  if (root_index == nullptr)
    {
      root_index = new ApvlvFileIndex ("", 0, "", FILE_INDEX_DIR);
    }

  GDir *dir = g_dir_open (path, 0, nullptr);
  if (dir != nullptr)
    {
      const gchar *name;
      while ((name = g_dir_read_name (dir)) != nullptr)
        {
          if (strcmp (name, ".") == 0)
            {
              debug ("avoid hidden file: %s", name);
              continue;
            }

          gchar *realname = g_strjoin (PATH_SEP_S, path, name, nullptr);
          struct stat buf[1];
          char *wrealname
              = g_locale_from_utf8 (realname, -1, nullptr, nullptr, nullptr);
          if (wrealname == nullptr)
            {
              g_free (realname);
              continue;
            }

          int ret = stat (wrealname, buf);
          g_free (wrealname);

          if (ret < 0)
            {
              g_free (realname);
              continue;
            }

          if (S_ISDIR (buf->st_mode))
            {
              auto index
                  = new ApvlvFileIndex (name, 0, realname, FILE_INDEX_DIR);
              root_index->children.push_back (index);
              newDirIndex (realname, index);
            }
          else if (g_ascii_strncasecmp (name + strlen (name) - 4, ".pdf", 4)
                       == 0
                   || g_ascii_strncasecmp (name + strlen (name) - 4, ".htm", 4)
                          == 0
                   || g_ascii_strncasecmp (name + strlen (name) - 5, ".html",
                                           5)
                          == 0
                   || g_ascii_strncasecmp (name + strlen (name) - 5, ".epub",
                                           5)
                          == 0
#ifdef APVLV_WITH_DJVU
                   || g_ascii_strncasecmp (name + strlen (name) - 5, ".djvu",
                                           5)
                          == 0
                   || g_ascii_strncasecmp (name + strlen (name) - 4, ".djv", 4)
                          == 0
#endif
#ifdef APVLV_WITH_TXT
                   || g_ascii_strncasecmp (name + strlen (name) - 4, ".txt", 4)
                          == 0
#endif
          )
            {
              auto index
                  = new ApvlvFileIndex (name, 0, realname, FILE_INDEX_FILE);
              root_index->children.push_back (index);
            }

          g_free (realname);
        }
    }
  g_dir_close (dir);

  return root_index;
}
ApvlvFileIndex::ApvlvFileIndex (string title, int page, string path,
                                ApvlvFileIndexType type)
{
  this->title = std::move (title);
  this->page = page;
  this->path = std::move (path);
  this->type = type;
}

ApvlvFileIndex::~ApvlvFileIndex ()
{
  for (auto *child : children)
    {
      delete child;
    }
}
}

// Local Variables:
// mode: c++
// End:
