/*
 *  Copyright 1994-2022 Olivier Girondel
 *
 *  This file is part of lebiniou.
 *
 *  lebiniou 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.
 *
 *  lebiniou 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 lebiniou. If not, see <http://www.gnu.org/licenses/>.
 */

#include <glib.h>
#include "bulfius.h"
#include "utils.h"
#include "defaults.h"


// #define DEBUG_BULFIUS_GET
#define STATIC_FILE_CHUNK 256


static const char *
content_type_from_ext(const char *ext)
{
  if (is_equal(ext, ".html")) {
    return "text/html";
  }
  if (is_equal(ext, ".css")) {
    return "text/css";
  }
  if (is_equal(ext, ".js") || is_equal(ext, ".map") || is_equal(ext, ".json")) {
    return "application/javascript";
  }
  if (is_equal(ext, ".gif")) {
    return "image/gif";
  }
  if (is_equal(ext, ".mp4")) {
    return "video/mp4";
  }
  if (is_equal(ext, ".png")) {
    return "image/png";
  }
  if (is_equal(ext, ".jpg") || is_equal(ext, ".jpeg")) {
    return "image/jpeg";
  }
  if (is_equal(ext, ".ico")) {
    return "image/x-icon";
  }
  if (is_equal(ext, ".svg")) {
    return "image/svg+xml";
  }

  return "application/octet-stream";
}


static const char *
get_filename_ext(const char *path)
{
  const char *dot = strrchr(path, '.');

  if ((NULL == dot) || (dot == path)) {
    return "*";
  }
  if (NULL != strchr(dot, '?')) {
    *strchr(dot, '?') = '\0';
  }

  return dot;
}


static ssize_t
callback_static_file_stream(void * cls, uint64_t pos, char * buf, size_t max)
{
  if (NULL != cls) {
    return fread(buf, 1, max, (FILE *)cls);
  } else {
    return U_STREAM_END;
  }
}


static void
callback_static_file_stream_free(void * cls)
{
  if (NULL != cls) {
    fclose((FILE *)cls);
  }
}


int
callback_vui_get_static(const struct _u_request *request, struct _u_response *response, void *user_data)
{
  size_t length;
  FILE *f;
  gchar *file_path = NULL;
  const char *content_type;
  const char *file = NULL;
  char *prefix = "";

  assert(NULL != user_data);
  if (user_data == (void *)BULFIUS_INDEX) {
    file = BULFIUS_INDEX_FILE;
  } else if (user_data == (void *)BULFIUS_FAVICO) {
    file = BULFIUS_FAVICO_ICO;
  } else {
    if (user_data == (void *)BULFIUS_CSS) {
      prefix = BULFIUS_CSS_ROOT;
    } else if (user_data == (void *)BULFIUS_IMG) {
      prefix = BULFIUS_IMG_ROOT;
    } else if (user_data == (void *)BULFIUS_JS) {
      prefix = BULFIUS_JS_ROOT;
    } else if (user_data == (void *)BULFIUS_MEDIA) {
      prefix = BULFIUS_MEDIA_ROOT;
    } else if (user_data == (void *)BULFIUS_DEMOS) {
      prefix = BULFIUS_DEMOS_ROOT;
    }
    file = u_map_get(request->map_url, "file");
  }

  if (getenv("DEV_WEB_UI")) {
    file_path = g_strdup_printf("./vue/%s/%s", prefix, file);
  } else {
    file_path = g_strdup_printf("%s/%s/%s", DEFAULT_VUEDIR, prefix, file);
  }
#ifdef DEBUG_BULFIUS_GET
  printf("=== %s: user_data= %p, prefix= '%s', file= '%s', file_path= '%s'\n", __func__, user_data, prefix, file, file_path);
#endif

  if ((NULL != file_path) && (access(file_path, F_OK) != -1)) {
    f = fopen (file_path, "rb");
    if (NULL != f) {
      fseek(f, 0, SEEK_END);
      length = ftell(f);
      fseek(f, 0, SEEK_SET);

      content_type = content_type_from_ext(get_filename_ext(file_path));
      ulfius_add_header_to_response(response, "Content-Type", content_type);
      ulfius_add_header_to_response(response, "Cache-Control", "no-cache,no-store,must-revalidate");
      ulfius_add_header_to_response(response, "Pragma", "no-cache");

      if (ulfius_set_stream_response(response, 200, callback_static_file_stream, callback_static_file_stream_free, length, STATIC_FILE_CHUNK, f) != U_OK) {
        fprintf(stderr, "[!] %s: callback_vui_get_static - Error ulfius_set_stream_response\n", __FILE__);
      }
      g_free(file_path);

      return U_CALLBACK_COMPLETE;
    }
  }

  return U_CALLBACK_ERROR;
}
