/*
 * Copyright 2022-2024 Frederico de Oliveira Linhares
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "candy_gear.hpp"

#include <mruby/array.h>
#include <mruby/hash.h>
#include <mruby/string.h>

#include "core.hpp"
#include "view_2d.hpp"
#include "view_3d.hpp"

static mrb_value
cg_mCandyGear_set_game_name(mrb_state *mrb, mrb_value self)
{
  mrb_value name;

  mrb_get_args(mrb, "S", &name);
  BluCat::INT::core.game_name = RSTRING_PTR(name);

  return self;
}

static mrb_value
cg_mCandyGear_set_views(mrb_state *mrb, mrb_value self)
{
  struct RClass *cg_m, *cg_cView2D, *cg_cView3D;
  mrb_value *array;
  mrb_int array_len;

  std::vector<std::shared_ptr<BluCat::GRA::View2D>> views_2d;
  std::vector<std::shared_ptr<BluCat::GRA::View3D>> views_3d;

  cg_m = mrb_module_get(mrb, "CandyGear");
  cg_cView2D = mrb_class_get_under(mrb, cg_m, "View2D");
  cg_cView3D = mrb_class_get_under(mrb, cg_m, "View3D");

  mrb_get_args(mrb, "a", &array, &array_len);
  for(mrb_int i{0}; i < array_len; i++)
  {
    if(mrb_obj_is_kind_of(mrb, array[i], cg_cView2D))
    {
      auto v = (std::shared_ptr<BluCat::GRA::View2D>*)DATA_PTR(array[i]);
      views_2d.push_back(*v);
    }
    else if(mrb_obj_is_kind_of(mrb, array[i], cg_cView3D))
    {
      auto v = (std::shared_ptr<BluCat::GRA::View3D>*)DATA_PTR(array[i]);
      views_3d.push_back(*v);
    }
  }

  // A Renderer need at least one view to work.
  if(views_2d.size() > 0 || views_3d.size() > 0)
  {
    delete BluCat::INT::core.vk_renderer;
    BluCat::INT::core.vk_renderer = new BluCat::GRA::Renderer({views_2d, views_3d});
  }

  return self;
}

static mrb_value
cg_mCandyGear_log(mrb_state *mrb, mrb_value self)
{
  const char *message;
  mrb_sym sym_log_level;
  Log::Level log_lvl;

  mrb_get_args(mrb, "nz", &sym_log_level, &message);

  if(sym_log_level == cg_core.sym_trace)
    log_lvl = Log::Level::Trace;
  else if(sym_log_level == cg_core.sym_debug)
    log_lvl = Log::Level::Debug;
  else if(sym_log_level == cg_core.sym_information)
    log_lvl = Log::Level::Information;
  else if(sym_log_level == cg_core.sym_warning)
    log_lvl = Log::Level::Warning;
  else if(sym_log_level == cg_core.sym_error)
    log_lvl = Log::Level::Error;
  else
    log_lvl = Log::Level::Fatal;

  BluCat::INT::core.log.message(log_lvl, message);

  return self;
}

static mrb_value
cg_mCandyGear_quit(mrb_state *mrb, mrb_value self)
{
  cg_core.quit_game = true;

  return self;
}

void
cg_candy_gear_init_config(mrb_state *mrb)
{
  struct RClass *cg_m;

  cg_m = mrb_module_get(mrb, "CandyGear");

  mrb_define_class_method(
    mrb, cg_m, "game_name=", cg_mCandyGear_set_game_name, MRB_ARGS_REQ(1));
}

void
cg_candy_gear_finish_config(mrb_state *mrb)
{
  struct RClass *cg_m;

  cg_m = mrb_module_get(mrb, "CandyGear");

  mrb_undef_class_method(mrb, cg_m, "game_name=");
}

void
cg_candy_gear_init(mrb_state *mrb)
{
  struct RClass *cg_m;

  cg_m = mrb_module_get(mrb, "CandyGear");

  mrb_define_class_method(
    mrb, cg_m, "views=", cg_mCandyGear_set_views, MRB_ARGS_REQ(1));
  mrb_define_class_method(
    mrb, cg_m, "log", cg_mCandyGear_log, MRB_ARGS_REQ(2));
  mrb_define_class_method(
    mrb, cg_m, "quit", cg_mCandyGear_quit, MRB_ARGS_NONE());
}