# Copyright 2023 Arkemis S.r.l.
#
# 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.
defmodule Arke do
alias Arke.Core.Unit
alias Arke.Boundary.{ArkeManager, GroupManager, ParameterManager}
alias Arke.System.BaseParameter
def init(), do: :ok
defp get_module(data,type) do
# get all the arke modules which has the arke macro defined
# find the right module for the given data and return it
arke_module_list = Enum.reduce(:application.loaded_applications(), [], fn {app, _, _}, arke_list ->
{:ok, modules} = :application.get_key(app, :modules)
function_name = get_module_fn(type)
module_arke_list =
Enum.reduce(modules, [], fn mod, mod_arke_list ->
if Code.ensure_loaded?(mod) and :erlang.function_exported(mod, function_name, 0) and
apply(mod, function_name,[]) != nil do
[%{module: mod, arke_id: apply(mod, function_name,[]).id} | mod_arke_list]
else
mod_arke_list
end
end)
arke_list ++ module_arke_list
end)
Enum.find(arke_module_list,%{module: nil, arke_id: nil}, fn k ->
if is_map(k) do
to_string(k.arke_id) == to_string(Map.get(data,:id))
end
end)[:module]
end
defp get_module_fn("arke"), do: :arke_from_attr
defp get_module_fn("group"), do: :group_from_attr
def handle_manager(_data,_project,_arke_id,_error\\[])
def handle_manager([data | t],project,:parameter,error)do
{type, updated_data} = Map.pop(data,:type)
final_data = BaseParameter.check_enum(type, updated_data) |> Enum.into(%{})
updated_error = start_manager(final_data,type,project,ParameterManager,nil)
handle_manager(t,project, :parameter,updated_error ++ error)
end
def handle_manager([data | t],project,:arke,error) do
{flatten_data,other} = Map.pop(data,:data,%{})
updated_data = Map.merge(flatten_data,other)
|> Map.put(:type,Map.get(data,:type,"arke"))
|> Map.put_new(:active,true)
final_data = Map.replace(updated_data,:parameters,parse_arke_parameter(updated_data,project))
module = get_module(final_data,"arke")
updated_error = start_manager(final_data,"arke",project,ArkeManager, module)
handle_manager(t,project, :arke,updated_error ++ error)
end
def handle_manager([data | t],project,:group,error)do
loaded_list = Enum.reduce(Map.get(data,:arke_list,[]),[], fn arke,acc ->
with %{id: id, metadata: _metadata}=link_data <- parse_group_member(arke),
%Unit{}= _arke_unit <- ArkeManager.get(id, project) do
[link_data | acc]
else
_ ->
[%{context: :arke_list_group , message: "invalid arke in arke_list of: `#{data.id}` in `#{project}`"} | error]
end
end)
final_data= Map.put(data,:arke_list,loaded_list)
module = get_module(final_data,"group")
updated_error = start_manager(final_data,"group",project,GroupManager,module)
handle_manager(t,project, :group,updated_error ++ error)
end
def handle_manager([],_project,_arke_id,error),do: error
defp parse_group_member(member) when is_binary(member), do: %{id: String.to_atom(member), metadata: %{}}
defp parse_group_member(member) when is_map(member) do
case Map.get(member,:id) do
nil -> {:error,"arke id not found"}
id -> %{id: id, metadata: Map.get(member, :metadata, %{})}
end
end
defp start_manager(_data,_type,_project, _manager, _module,_error\\[])
defp start_manager(data,type,project, manager, module,error) do
case Map.pop(data,:id,nil) do
{nil, _updated_data} -> [%{context: :manager , message: "key id not found"} | error]
{id, updated_data} ->
{metadata,updated_data} = Map.pop(updated_data,:metadata,%{project: project})
case manager.create(
Unit.new(
String.to_atom(id),
updated_data,
String.to_atom(type),
nil,
metadata,
nil,
nil,
module
),
project
) do
%Unit{} = _unit ->
error
_ ->[%{context: :manager , message: "cannot start manager for: `#{id}`"} | error]
end
end
end
defp parse_arke_parameter(data,project) do
base_parameters(Map.get(data,:parameters,[]), Map.get(data,:type,"arke")) |> Enum.reduce([], fn param,acc ->
# controllare anche che il parameter manager torni qualcosa che esiste
converted = Map.update(param,:id, "tbd", &String.to_atom(to_string(&1)))
id = converted[:id]
case ParameterManager.get(id,project) do
%Unit{} = arke ->
type = arke.arke_id
final_data = Map.update(converted,:metadata,%{}, &(
BaseParameter.check_enum(type, &1) |>
Enum.into(%{}))
)
|> Map.put(:arke, type)
[ final_data | acc]
_ -> acc
end
end)
end
defp base_parameters(arke_parameters,"arke") do
arke_parameters ++ [
%{id: "id", metadata: %{required: true, persistence: "table_column"}},
%{id: "arke_id", metadata: %{required: false, persistence: "table_column"}},
%{id: "metadata", metadata: %{required: false, persistence: "table_column"}},
%{id: "inserted_at", metadata: %{required: false, persistence: "table_column"}},
%{id: "updated_at", metadata: %{required: false, persistence: "table_column"}}]
end
defp base_parameters(arke_parameters, _type), do: arke_parameters
end